Update readme, imported code.
authorJimmy Christensen <dusted@dusted.dk>
Wed, 23 Dec 2015 21:03:14 +0000 (22:03 +0100)
committerJimmy Christensen <dusted@dusted.dk>
Wed, 23 Dec 2015 21:18:30 +0000 (22:18 +0100)
34 files changed:
README.md
src/Acorn.c [new file with mode: 0644]
src/Acorn.h [new file with mode: 0644]
src/AmiDevCPP/Makefile.win [new file with mode: 0644]
src/AmiDevCPP/UberCassette.dev [new file with mode: 0644]
src/AmiDevCPP/UberCassette.layout [new file with mode: 0644]
src/Amstrad.c [new file with mode: 0644]
src/Amstrad.h [new file with mode: 0644]
src/CBM.c [new file with mode: 0644]
src/CBM.h [new file with mode: 0644]
src/CSW.c [new file with mode: 0644]
src/CSW.h [new file with mode: 0644]
src/Machines.h [new file with mode: 0644]
src/Makefile [new file with mode: 0644]
src/Sample.c [new file with mode: 0644]
src/Sample.c.bak.c [new file with mode: 0644]
src/Sample.h [new file with mode: 0644]
src/Spectrum.c [new file with mode: 0644]
src/Spectrum.h [new file with mode: 0644]
src/T64.c [new file with mode: 0644]
src/T64.h [new file with mode: 0644]
src/TAP.c [new file with mode: 0644]
src/TAP.h [new file with mode: 0644]
src/TZX.c [new file with mode: 0644]
src/TZX.h [new file with mode: 0644]
src/UEF.c [new file with mode: 0644]
src/UEF.h [new file with mode: 0644]
src/UberCassette.h [new file with mode: 0644]
src/UberCassette.sln [new file with mode: 0644]
src/UberCassette.vcproj [new file with mode: 0644]
src/WAV.c [new file with mode: 0644]
src/WAV.h [new file with mode: 0644]
src/linkermap [new file with mode: 0644]
src/main.c [new file with mode: 0644]

index 99be0f4..79f4003 100644 (file)
--- a/README.md
+++ b/README.md
@@ -1,2 +1,40 @@
-# ubercassette
-Awesome WAV to Commodore64 TAP converter
+# UberCassette
+Awesome WAV to Commodore64 TAP converter, written by Ian Gledhill. Thanks to Ian for putting the sauce online, if you find this software useful, visit his page and send a donation his way!
+
+Official website: http://www.retroreview.com/iang/UberCassette/
+
+# What it is for
+It's for when you want to transfer your Commodore 64 tapes onto your modern PC.
+
+After recording the tape into your computer, you should end up with a WAV file,
+ubercassette can convert the WAV to the well-supported TAP format, which can
+be used on emulators, and can also be converted back to WAV for use with a C64
+at a later time.
+
+# Why I put it here
+Because it's an awesome program, and this way I know how to find it again later.
+
+# How to use it
+First, you need a cassette player, anything that you can connect to your computer is most likely fine.
+
+* Plugged it in my PC, and the device presented itself as an USB microphone.
+* Fired up Audacity, and set it for recording 44100 hz mono from the USB microphone device (the Cassette to MP3 Converter).
+* Pressed record in Audacity, pressed Play on the Cassette player.
+* Finished recording, exported audio to turtles-side1.wav
+
+```bash
+
+# Build ubercassette like so:
+cd src
+make
+cd ..
+
+# Used ubercassette like so:
+./ubercassette turtles-side1.wav turtles-side1.tap
+```
+
+Easy!
+
+# A note on my cassette player
+I used a cheap "Cassette to MP3 Converter" it had a label "MODEL NO.: RC-2765" but it's from China, so I don't know if it means anything to anyone, but it is a silver-gray walkman style device, which takes 2 AA batteries, has a 3.5 mm Jack for headphones, a mini-usb plug, a volume control, playback-controls and a DC3V power connector (for which no AC adapter came). The player worked perfectly, and I did not have to clean up the audio before using it.
+
diff --git a/src/Acorn.c b/src/Acorn.c
new file mode 100644 (file)
index 0000000..513e84a
--- /dev/null
@@ -0,0 +1,322 @@
+#include <stdio.h>\r
+#include <stdlib.h>\r
+\r
+#include <math.h>\r
+\r
+#include "UberCassette.h"\r
+#include "WAV.h"\r
+#include "Sample.h"\r
+#include "Acorn.h"\r
+\r
+struct Acorn_CassetteBlock *gAcorn_CassetteBlockList = NULL;\r
+\r
+const unsigned char cDummyByte[] = { 0,0,0, 1,1, 0,0,1,0,0,1,0,0,1,0,0,1,-1 };\r
+\r
+#define MAX_WAVELENGTH 2000.0f\r
+\r
+unsigned char *Acorn_ParseWAV( unsigned char *wavData )\r
+{\r
+       unsigned char *tParsedData = NULL;\r
+       struct RAW_Format tRawData;\r
+\r
+       // First off, extract the RAW data.\r
+       tRawData = WAV_GetRAW( wavData, true );\r
+\r
+       // First we scan the entire file for the wavelength of the header.\r
+       BuildWavelengthTable( tRawData, 0, -1, gWaveLengthTable );\r
+\r
+       // Work out our thresholds....\r
+       BuildThresholds( tRawData, 2, &gThresholds[ 0 ], gWaveLengthTable, gSample_ValueTable );\r
+\r
+       if ( gAlgorithmType == TRIGGER )\r
+               BuildRawWaveList( tRawData, 0, NULL, -1, false );\r
+       else \r
+               BuildRawWaveList_Cleaned( tRawData, 0, NULL, -1, false );\r
+\r
+       // Now we have lovely 8-bit mono raw data.\r
+       Acorn_BuildTapeBlocks( tRawData );\r
+\r
+       return (unsigned char *)1;\r
+}\r
+\r
+void Acorn_BuildTapeBlocks( struct RAW_Format format )\r
+{\r
+       int tPointer = 0;\r
+       int *tRawPointer = &gRawCycles[ tPointer ];\r
+       int tHeaderCycles = -1, tHeaderStart = -1, tDummyCycles = -1;\r
+       enum State { STATE_NOSIGNAL, STATE_HEADERSTART, STATE_DUMMYBYTE, STATE_HEADER, STATE_TRAILER, STATE_DATA, STATE_DATA_WAITING_START_BIT, STATE_DATA_WAITING_STOP_BIT } tState = STATE_NOSIGNAL;\r
+       unsigned char tBytes[ 128 * 1024 ];\r
+       signed long tValue;\r
+       char *tBytePointer = &tBytes[ 0 ];\r
+       int tBits = 0, tHalfBits = 0, tParity = 0;\r
+       int tDelayCycles = 0;\r
+\r
+       *tBytePointer = 0;\r
+\r
+    //printf( "Building Acorn blocks. Size is %ld.\n", gRawLength );\r
+\r
+       while ( tPointer < gRawLength )\r
+       {\r
+               if ( tPointer == 172 )\r
+               {\r
+                       bool test=true;\r
+               }\r
+\r
+               if ( *tRawPointer < NUMBER_OF_THRESHOLDS )\r
+                       tValue = gSample_ValueTable[ (int)*tRawPointer ];\r
+               else\r
+                       tValue = -1; // Invalid wave length.\r
+\r
+               switch ( tState )\r
+               {\r
+               case STATE_NOSIGNAL:\r
+               {\r
+                       tDelayCycles += (int)*tRawPointer;\r
+                       if ( tValue == 0 )\r
+                       {\r
+                               tHeaderCycles++;\r
+                               if ( tHeaderCycles > 1 )        // The first wave is rarely formed correctly.\r
+                               {\r
+                                       tState = STATE_HEADERSTART;\r
+                                       tHeaderStart = tPointer - 3;\r
+                                       tDummyCycles = 3;\r
+                                       //tDelayCycles -= (int)*(tRawPointer-1);\r
+                                       //tDelayCycles -= (int)*(tRawPointer-2);\r
+                               }\r
+                       }\r
+                       else\r
+                       {\r
+                               if ( tDelayCycles < 0 )\r
+                               {\r
+                                       printf( "Error in Acorn cycles.\n" );\r
+                               }\r
+                               tHeaderCycles = 0;\r
+                               tDummyCycles = 0;\r
+//                             printf( " Adding %d cycles (%f Seconds).\n", tDelayCycles, (float)tDelayCycles / (float)gWAVFormat.sampleRate );\r
+                       }\r
+                       break;\r
+               }\r
+               case STATE_HEADERSTART:\r
+               {\r
+                       if ( tValue == cDummyByte[ tDummyCycles ] )\r
+                       {\r
+                               tDummyCycles++;\r
+                               if ( tValue != 0 )\r
+                                       tHeaderCycles = 0;\r
+                       }\r
+                       else if ( tValue == 0 )\r
+                       {\r
+                               tHeaderCycles++;\r
+                               tDummyCycles = 0;\r
+                       }\r
+                       else\r
+                       {\r
+                               tState = STATE_NOSIGNAL;\r
+                               break;\r
+                       }\r
+\r
+                       if ( tDummyCycles > 16 )\r
+                       {\r
+                               tState = STATE_DUMMYBYTE;\r
+                               Acorn_AddPause( tDelayCycles );\r
+                               tDelayCycles = 0;               \r
+                       }\r
+                       else if ( tHeaderCycles > 7 )\r
+                       {\r
+                               int *tHeaderPointer = tRawPointer - 8;\r
+                               // Valid header!\r
+                               tState = STATE_HEADER;\r
+                               tHeaderStart = tPointer - 8;\r
+\r
+                               Acorn_AddPause( tDelayCycles );\r
+                               tDelayCycles = 0;               \r
+                       }\r
+                       break;\r
+               }\r
+               case STATE_DUMMYBYTE:\r
+               case STATE_HEADER:\r
+               {\r
+                       if ( tValue == 0 )\r
+                       {\r
+                               tHeaderCycles++;\r
+                       }\r
+                       else\r
+                       {\r
+                               if ( tState == STATE_DUMMYBYTE && tValue == 1 )\r
+                               {\r
+                                       if ( tHeaderCycles < 8 )\r
+                                       {\r
+                                               // It's a dummy byte. Takes a while to settle down.\r
+                                               tHeaderCycles = 0;\r
+                                               break;\r
+                                       }\r
+                               }\r
+                               // End of the header!\r
+                               if ( tState == STATE_DUMMYBYTE )\r
+                                       Acorn_AddHeaderCycles( tHeaderCycles, true );\r
+                               else\r
+                                       Acorn_AddHeaderCycles( tHeaderCycles, false );\r
+                                       \r
+                               if ( tValue == 1 )\r
+                                       tState = STATE_DATA;\r
+                               else\r
+                                       tState = STATE_NOSIGNAL;\r
+\r
+                               tHeaderCycles = 0;\r
+                               tBits = 0;\r
+                               tHalfBits = 0;\r
+                       }\r
+                       break;\r
+               }\r
+               case STATE_DATA:\r
+               {\r
+                       // We've done the start bit (0).\r
+                       if ( tValue == 0 )\r
+                       {\r
+                               // 1 bit.\r
+                               tHalfBits = 1 - tHalfBits;\r
+                               if ( tHalfBits == 0 )\r
+                               {\r
+                                       *tBytePointer |= ( 1 << tBits );\r
+                                       tBits++;\r
+                                       tParity = 1 - tParity;\r
+                               }\r
+                       }\r
+                       else\r
+                       {\r
+                               tHalfBits = 0;\r
+                               tBits++;\r
+                       }\r
+\r
+                       if ( tBits == 8 )\r
+                       {\r
+                               tBytePointer++;\r
+                               *tBytePointer = 0;\r
+                               tBits = 0;\r
+                               tState = STATE_DATA_WAITING_STOP_BIT;\r
+                       }\r
+                       break;\r
+               }\r
+               case STATE_DATA_WAITING_START_BIT:\r
+               {\r
+                       if ( tValue == 0 )\r
+                       {\r
+                               if ( tBytePointer != (char *)tBytes )\r
+                               {\r
+                                       Acorn_AddDataBlock( tBytePointer - (char *)tBytes, tBytes );\r
+                                       tHeaderCycles = 0;\r
+                                       tState = STATE_TRAILER;\r
+                                       tBytePointer = tBytes;\r
+                               }\r
+                               else\r
+                                       tState = STATE_NOSIGNAL;\r
+                       }\r
+                       else\r
+                               tState = STATE_DATA;\r
+                       break;\r
+               }\r
+               case STATE_TRAILER:\r
+               {\r
+                       if ( tValue == -1 || *tRawPointer > MAX_WAVELENGTH )//*(tRawPointer+1) > MAX_WAVELENGTH || *(tRawPointer+2) > MAX_WAVELENGTH || *(tRawPointer+3) > MAX_WAVELENGTH || *(tRawPointer+4) > MAX_WAVELENGTH || *(tRawPointer+5) > MAX_WAVELENGTH)\r
+                       {\r
+                               tState = STATE_NOSIGNAL;\r
+                               Acorn_AddHeaderCycles( tHeaderCycles, false );\r
+                               tHeaderCycles = 0;\r
+                               tDelayCycles = 0;\r
+                       }\r
+                       else if ( tValue == 0 )\r
+                       {\r
+                               tHeaderCycles++;\r
+                       }\r
+                       else if ( tValue == 1 )\r
+                       {\r
+                               Acorn_AddHeaderCycles( tHeaderCycles, false );\r
+                               tHeaderCycles = 0;      \r
+\r
+                               if ( tValue == 1 )\r
+                                       tState = STATE_DATA;\r
+                       }\r
+                       break;\r
+               }\r
+               case STATE_DATA_WAITING_STOP_BIT:\r
+               {\r
+                       if ( tValue == 0 )\r
+                       {\r
+                               tHalfBits = 1 - tHalfBits;\r
+                               if ( tHalfBits == 0 )\r
+                               {\r
+                                       tState = STATE_DATA_WAITING_START_BIT;\r
+                               }\r
+                       }\r
+                       else\r
+                               tState = STATE_NOSIGNAL;\r
+                       break;\r
+               }\r
+               default:\r
+                       break;\r
+               }\r
+\r
+               tRawPointer++;\r
+               tPointer++;\r
+       }\r
+       \r
+       printf( "Done.\n" );\r
+}\r
+\r
+void Acorn_AddHeaderCycles( int cycles, bool dummy )\r
+{\r
+//     printf( "Found header of %d cycles.\n", cycles );\r
+       if ( dummy )\r
+               Acorn_AddBlock( ACBT_DUMMYBYTE, cycles, NULL );\r
+       else\r
+               Acorn_AddBlock( ACBT_HEADER, cycles, NULL );\r
+}\r
+\r
+void Acorn_AddDataBlock( int size, char *data )\r
+{\r
+       unsigned char *tBuffer;\r
+\r
+       tBuffer = (unsigned char *)malloc( size );\r
+       if ( tBuffer == NULL )\r
+    {\r
+        printf( "Out of memory in Acorn_AddDataBlock.\n" );\r
+        return;\r
+       }\r
+    memcpy( tBuffer, data, size );\r
+\r
+       Acorn_AddBlock( ACBT_DATA, size, tBuffer );\r
+}\r
+\r
+void Acorn_AddBlock( enum Acorn_CassetteBlockType type, int size, unsigned char *data )\r
+{\r
+       struct Acorn_CassetteBlock *tNode = gAcorn_CassetteBlockList;\r
+\r
+       while ( tNode )\r
+       {\r
+               if ( tNode->next )\r
+                       tNode = tNode->next;\r
+               else\r
+                       break;\r
+       }\r
+\r
+       if ( gAcorn_CassetteBlockList == NULL )\r
+               tNode = gAcorn_CassetteBlockList = (struct Acorn_CassetteBlock *)malloc( sizeof( struct Acorn_CassetteBlock ) );\r
+       else\r
+       {\r
+               tNode->next = (struct Acorn_CassetteBlock *)malloc( sizeof( struct Acorn_CassetteBlock ) );\r
+               tNode = tNode->next;\r
+       }\r
+\r
+       tNode->type = type;\r
+       tNode->sizeUnion.size = size;\r
+       tNode->data = data;\r
+       tNode->next = NULL;\r
+}\r
+\r
+void Acorn_AddPause( int size )\r
+{\r
+       float tLengthInSeconds = (float)(ConvertFromCyclesToSeconds( size ));\r
+\r
+       Acorn_AddBlock( ACBT_PAUSE, *((int*)&tLengthInSeconds), NULL );\r
+\r
+}\r
diff --git a/src/Acorn.h b/src/Acorn.h
new file mode 100644 (file)
index 0000000..8e1f6c2
--- /dev/null
@@ -0,0 +1,23 @@
+enum Acorn_CassetteBlockType { ACBT_HEADER, ACBT_DUMMYBYTE, ACBT_DATA, ACBT_PAUSE };\r
+\r
+struct Acorn_CassetteBlock\r
+{\r
+       enum Acorn_CassetteBlockType type;\r
+       union\r
+       {\r
+               int size;\r
+               float seconds;\r
+       } sizeUnion;\r
+       unsigned char *data;\r
+       struct Acorn_CassetteBlock *next;\r
+};\r
+\r
+\r
+extern struct Acorn_CassetteBlock *gAcorn_CassetteBlockList;\r
+\r
+unsigned char *Acorn_ParseWAV( unsigned char *rawData );\r
+void Acorn_BuildTapeBlocks( struct RAW_Format format );\r
+void Acorn_AddHeaderCycles( int cycles, bool dummy );\r
+void Acorn_AddBlock( enum Acorn_CassetteBlockType type, int cycles, unsigned char *data );\r
+void Acorn_AddDataBlock( int size, char *data );\r
+void Acorn_AddPause( int size );\r
diff --git a/src/AmiDevCPP/Makefile.win b/src/AmiDevCPP/Makefile.win
new file mode 100644 (file)
index 0000000..d806450
--- /dev/null
@@ -0,0 +1,66 @@
+# Project: UberCassette\r
+# Compiler: i686-AROS\r
+# Compiler Type: MingW 3\r
+# Makefile created by wxDev-C++ 6.10.2 on 16/03/11 17:13\r
+\r
+CPP       = i386-aros-g++.exe\r
+CC        = i386-aros-gcc.exe\r
+WINDRES   = windres.exe\r
+OBJ       = ../Acorn.o ../CBM.o ../main.o ../Sample.o ../T64.o ../TAP.o ../UEF.o ../WAV.o ../Amstrad.o ../CSW.o ../Spectrum.o ../TZX.o\r
+LINKOBJ   = ../Acorn.o ../CBM.o ../main.o ../Sample.o ../T64.o ../TAP.o ../UEF.o ../WAV.o ../Amstrad.o ../CSW.o ../Spectrum.o ../TZX.o\r
+LIBS      = -L"C:/CrossCompiler/AmiDevCpp/usr/local/amiga/i386-aros/lib" -lm -noixemul  \r
+INCS      = -I"C:/CrossCompiler/AmiDevCpp/usr/local/amiga/i386-aros/sys-include"\r
+CXXINCS   = -I"C:/CrossCompiler/AmiDevCpp/usr/local/amiga/i386-aros/sys-include"\r
+RCINCS    = --include-dir "C:/CROSSC~1/AMIDEV~1/include"\r
+BIN       = UberCassette.exe\r
+DEFINES   =  -D_DUMP_RAW\r
+CXXFLAGS  = $(CXXINCS) $(DEFINES)   -O3\r
+CFLAGS    = $(INCS) $(DEFINES)   -O3\r
+GPROF     = gprof.exe\r
+RM        = rm -f\r
+LINK      = i386-aros-g++.exe\r
+\r
+.PHONY: all all-before all-after clean clean-custom\r
+all: all-before $(BIN) all-after\r
+\r
+clean: clean-custom\r
+       $(RM) $(OBJ) $(BIN)\r
+\r
+$(BIN): $(OBJ)\r
+       $(LINK) $(LINKOBJ) -o "UberCassette.exe" $(LIBS)\r
+\r
+../Acorn.o: $(GLOBALDEPS) ../Acorn.c\r
+       $(CC) -c ../Acorn.c -o ../Acorn.o $(CFLAGS)\r
+\r
+../CBM.o: $(GLOBALDEPS) ../CBM.c\r
+       $(CC) -c ../CBM.c -o ../CBM.o $(CFLAGS)\r
+\r
+../main.o: $(GLOBALDEPS) ../main.c\r
+       $(CC) -c ../main.c -o ../main.o $(CFLAGS)\r
+\r
+../Sample.o: $(GLOBALDEPS) ../Sample.c\r
+       $(CC) -c ../Sample.c -o ../Sample.o $(CFLAGS)\r
+\r
+../T64.o: $(GLOBALDEPS) ../T64.c\r
+       $(CC) -c ../T64.c -o ../T64.o $(CFLAGS)\r
+\r
+../TAP.o: $(GLOBALDEPS) ../TAP.c\r
+       $(CC) -c ../TAP.c -o ../TAP.o $(CFLAGS)\r
+\r
+../UEF.o: $(GLOBALDEPS) ../UEF.c\r
+       $(CC) -c ../UEF.c -o ../UEF.o $(CFLAGS)\r
+\r
+../WAV.o: $(GLOBALDEPS) ../WAV.c\r
+       $(CC) -c ../WAV.c -o ../WAV.o $(CFLAGS)\r
+\r
+../Amstrad.o: $(GLOBALDEPS) ../Amstrad.c\r
+       $(CC) -c ../Amstrad.c -o ../Amstrad.o $(CFLAGS)\r
+\r
+../CSW.o: $(GLOBALDEPS) ../CSW.c\r
+       $(CC) -c ../CSW.c -o ../CSW.o $(CFLAGS)\r
+\r
+../Spectrum.o: $(GLOBALDEPS) ../Spectrum.c\r
+       $(CC) -c ../Spectrum.c -o ../Spectrum.o $(CFLAGS)\r
+\r
+../TZX.o: $(GLOBALDEPS) ../TZX.c\r
+       $(CC) -c ../TZX.c -o ../TZX.o $(CFLAGS)\r
diff --git a/src/AmiDevCPP/UberCassette.dev b/src/AmiDevCPP/UberCassette.dev
new file mode 100644 (file)
index 0000000..5b611f9
--- /dev/null
@@ -0,0 +1,308 @@
+[Project]\r
+FileName=UberCassette.dev\r
+Name=UberCassette\r
+UnitCount=25\r
+PchHead=-1\r
+PchSource=-1\r
+Ver=3\r
+IsCpp=1\r
+ProfilesCount=1\r
+ProfileIndex=0\r
+Folders=\r
+\r
+[Unit1]\r
+FileName=..\Acorn.c\r
+CompileCpp=0\r
+Folder=UberCassette\r
+Compile=1\r
+Link=1\r
+Priority=1000\r
+OverrideBuildCmd=0\r
+BuildCmd=\r
+\r
+[Unit2]\r
+FileName=..\Acorn.h\r
+CompileCpp=0\r
+Folder=UberCassette\r
+Compile=1\r
+Link=1\r
+Priority=1000\r
+OverrideBuildCmd=0\r
+BuildCmd=\r
+\r
+[Unit3]\r
+FileName=..\CBM.c\r
+CompileCpp=0\r
+Folder=UberCassette\r
+Compile=1\r
+Link=1\r
+Priority=1000\r
+OverrideBuildCmd=0\r
+BuildCmd=\r
+\r
+[Unit4]\r
+FileName=..\CBM.h\r
+CompileCpp=0\r
+Folder=UberCassette\r
+Compile=1\r
+Link=1\r
+Priority=1000\r
+OverrideBuildCmd=0\r
+BuildCmd=\r
+\r
+[Unit5]\r
+FileName=..\Machines.h\r
+CompileCpp=0\r
+Folder=UberCassette\r
+Compile=1\r
+Link=1\r
+Priority=1000\r
+OverrideBuildCmd=0\r
+BuildCmd=\r
+\r
+[Unit6]\r
+FileName=..\main.c\r
+CompileCpp=0\r
+Folder=UberCassette\r
+Compile=1\r
+Link=1\r
+Priority=1000\r
+OverrideBuildCmd=0\r
+BuildCmd=\r
+\r
+[Unit7]\r
+FileName=..\Sample.c\r
+CompileCpp=0\r
+Folder=UberCassette\r
+Compile=1\r
+Link=1\r
+Priority=1000\r
+OverrideBuildCmd=0\r
+BuildCmd=\r
+\r
+[Unit8]\r
+FileName=..\Sample.h\r
+CompileCpp=0\r
+Folder=UberCassette\r
+Compile=1\r
+Link=1\r
+Priority=1000\r
+OverrideBuildCmd=0\r
+BuildCmd=\r
+\r
+[Unit9]\r
+FileName=..\T64.c\r
+CompileCpp=0\r
+Folder=UberCassette\r
+Compile=1\r
+Link=1\r
+Priority=1000\r
+OverrideBuildCmd=0\r
+BuildCmd=\r
+\r
+[Unit10]\r
+FileName=..\T64.h\r
+CompileCpp=0\r
+Folder=UberCassette\r
+Compile=1\r
+Link=1\r
+Priority=1000\r
+OverrideBuildCmd=0\r
+BuildCmd=\r
+\r
+[Unit11]\r
+FileName=..\TAP.c\r
+CompileCpp=0\r
+Folder=UberCassette\r
+Compile=1\r
+Link=1\r
+Priority=1000\r
+OverrideBuildCmd=0\r
+BuildCmd=\r
+\r
+[Unit12]\r
+FileName=..\TAP.h\r
+CompileCpp=0\r
+Folder=UberCassette\r
+Compile=1\r
+Link=1\r
+Priority=1000\r
+OverrideBuildCmd=0\r
+BuildCmd=\r
+\r
+[Unit13]\r
+FileName=..\UberCassette.h\r
+CompileCpp=0\r
+Folder=UberCassette\r
+Compile=1\r
+Link=1\r
+Priority=1000\r
+OverrideBuildCmd=0\r
+BuildCmd=\r
+\r
+[Unit14]\r
+FileName=..\UEF.c\r
+CompileCpp=0\r
+Folder=UberCassette\r
+Compile=1\r
+Link=1\r
+Priority=1000\r
+OverrideBuildCmd=0\r
+BuildCmd=\r
+\r
+[Unit15]\r
+FileName=..\UEF.h\r
+CompileCpp=0\r
+Folder=UberCassette\r
+Compile=1\r
+Link=1\r
+Priority=1000\r
+OverrideBuildCmd=0\r
+BuildCmd=\r
+\r
+[Unit16]\r
+FileName=..\WAV.c\r
+CompileCpp=0\r
+Folder=UberCassette\r
+Compile=1\r
+Link=1\r
+Priority=1000\r
+OverrideBuildCmd=0\r
+BuildCmd=\r
+\r
+[Unit17]\r
+FileName=..\WAV.h\r
+CompileCpp=0\r
+Folder=UberCassette\r
+Compile=1\r
+Link=1\r
+Priority=1000\r
+OverrideBuildCmd=0\r
+BuildCmd=\r
+\r
+[VersionInfo]\r
+Major=0\r
+Minor=1\r
+Release=1\r
+Build=1\r
+LanguageID=1033\r
+CharsetID=1252\r
+CompanyName=\r
+FileVersion=\r
+FileDescription=\r
+InternalName=\r
+LegalCopyright=\r
+LegalTrademarks=\r
+OriginalFilename=\r
+ProductName=\r
+ProductVersion=\r
+AutoIncBuildNrOnRebuild=0\r
+AutoIncBuildNrOnCompile=0\r
+\r
+[Profile1]\r
+ProfileName=Amiga_m68k\r
+Type=1\r
+ObjFiles=\r
+Includes=\r
+Libs=\r
+ResourceIncludes=\r
+MakeIncludes=\r
+Compiler=\r
+CppCompiler=\r
+Linker=-lm -noixemul_@@_\r
+PreprocDefines=_DUMP_RAW_@@_\r
+CompilerSettings=0000000000001000000000\r
+Icon=\r
+ExeOutput=\r
+ObjectOutput=\r
+OverrideOutput=0\r
+OverrideOutputName=UberCassette\r
+HostApplication=\r
+CommandLine=\r
+UseCustomMakefile=0\r
+CustomMakefile=\r
+IncludeVersionInfo=0\r
+SupportXPThemes=0\r
+CompilerSet=2\r
+compilerType=0\r
+\r
+[Unit22]\r
+FileName=..\Amstrad.c\r
+CompileCpp=0\r
+Folder=UberCassette\r
+Compile=1\r
+Link=1\r
+Priority=1000\r
+OverrideBuildCmd=0\r
+BuildCmd=\r
+\r
+[Unit23]\r
+FileName=..\CSW.c\r
+CompileCpp=0\r
+Folder=UberCassette\r
+Compile=1\r
+Link=1\r
+Priority=1000\r
+OverrideBuildCmd=0\r
+BuildCmd=\r
+\r
+[Unit24]\r
+FileName=..\Spectrum.c\r
+CompileCpp=0\r
+Folder=UberCassette\r
+Compile=1\r
+Link=1\r
+Priority=1000\r
+OverrideBuildCmd=0\r
+BuildCmd=\r
+\r
+[Unit25]\r
+FileName=..\TZX.c\r
+CompileCpp=0\r
+Folder=UberCassette\r
+Compile=1\r
+Link=1\r
+Priority=1000\r
+OverrideBuildCmd=0\r
+BuildCmd=\r
+\r
+[Unit18]\r
+FileName=..\Amstrad.h\r
+CompileCpp=0\r
+Folder=UberCassette\r
+Compile=1\r
+Link=1\r
+Priority=1000\r
+OverrideBuildCmd=0\r
+BuildCmd=\r
+\r
+[Unit19]\r
+FileName=..\CSW.h\r
+CompileCpp=0\r
+Folder=UberCassette\r
+Compile=1\r
+Link=1\r
+Priority=1000\r
+OverrideBuildCmd=0\r
+BuildCmd=\r
+\r
+[Unit20]\r
+FileName=..\Spectrum.h\r
+CompileCpp=0\r
+Folder=UberCassette\r
+Compile=1\r
+Link=1\r
+Priority=1000\r
+OverrideBuildCmd=0\r
+BuildCmd=\r
+\r
+[Unit21]\r
+FileName=..\TZX.h\r
+CompileCpp=0\r
+Folder=UberCassette\r
+Compile=1\r
+Link=1\r
+Priority=1000\r
+OverrideBuildCmd=0\r
+BuildCmd=\r
+\r
diff --git a/src/AmiDevCPP/UberCassette.layout b/src/AmiDevCPP/UberCassette.layout
new file mode 100644 (file)
index 0000000..0eeab83
--- /dev/null
@@ -0,0 +1,174 @@
+[Editor_0]\r
+CursorCol=1\r
+CursorRow=6\r
+TopLine=6\r
+LeftChar=1\r
+Open=0\r
+Top=0\r
+[Editors]\r
+Order=-1\r
+Focused=-1\r
+[Editor_1]\r
+Open=0\r
+Top=0\r
+CursorCol=1\r
+CursorRow=24\r
+TopLine=1\r
+LeftChar=1\r
+[Editor_2]\r
+Open=0\r
+Top=0\r
+CursorCol=23\r
+CursorRow=30\r
+TopLine=1\r
+LeftChar=1\r
+[Editor_3]\r
+Open=0\r
+Top=0\r
+CursorCol=1\r
+CursorRow=2\r
+TopLine=1\r
+LeftChar=1\r
+[Editor_4]\r
+Open=0\r
+Top=0\r
+CursorCol=3\r
+CursorRow=35\r
+TopLine=1\r
+LeftChar=1\r
+[Editor_5]\r
+Open=0\r
+Top=0\r
+CursorCol=3\r
+CursorRow=361\r
+TopLine=312\r
+LeftChar=1\r
+[Editor_6]\r
+Open=0\r
+Top=0\r
+CursorCol=26\r
+CursorRow=7\r
+TopLine=1\r
+LeftChar=1\r
+[Editor_7]\r
+Open=0\r
+Top=0\r
+CursorCol=1\r
+CursorRow=21\r
+TopLine=1\r
+LeftChar=1\r
+[Editor_8]\r
+Open=0\r
+Top=0\r
+CursorCol=30\r
+CursorRow=27\r
+TopLine=1\r
+LeftChar=1\r
+[Editor_9]\r
+Open=0\r
+Top=0\r
+CursorCol=1\r
+CursorRow=2\r
+TopLine=1\r
+LeftChar=1\r
+[Editor_10]\r
+Open=0\r
+Top=0\r
+CursorCol=1\r
+CursorRow=146\r
+TopLine=97\r
+LeftChar=1\r
+[Editor_11]\r
+Open=0\r
+Top=0\r
+CursorCol=1\r
+CursorRow=2\r
+TopLine=1\r
+LeftChar=1\r
+[Editor_12]\r
+Open=0\r
+Top=0\r
+CursorCol=1\r
+CursorRow=27\r
+TopLine=19\r
+LeftChar=1\r
+[Editor_13]\r
+Open=0\r
+Top=0\r
+CursorCol=24\r
+CursorRow=13\r
+TopLine=1\r
+LeftChar=1\r
+[Editor_14]\r
+Open=0\r
+Top=0\r
+CursorCol=1\r
+CursorRow=2\r
+TopLine=1\r
+LeftChar=1\r
+[Editor_15]\r
+Open=0\r
+Top=0\r
+CursorCol=3\r
+CursorRow=99\r
+TopLine=88\r
+LeftChar=1\r
+[Editor_16]\r
+Open=0\r
+Top=0\r
+CursorCol=3\r
+CursorRow=17\r
+TopLine=1\r
+LeftChar=1\r
+[Editor_17]\r
+Open=0\r
+Top=0\r
+CursorCol=1\r
+CursorRow=11\r
+TopLine=1\r
+LeftChar=1\r
+[Editor_18]\r
+Open=0\r
+Top=0\r
+CursorCol=1\r
+CursorRow=8\r
+TopLine=1\r
+LeftChar=1\r
+[Editor_19]\r
+Open=0\r
+Top=0\r
+CursorCol=27\r
+CursorRow=122\r
+TopLine=73\r
+LeftChar=1\r
+[Editor_20]\r
+Open=1\r
+Top=1\r
+CursorCol=1\r
+CursorRow=5\r
+TopLine=1\r
+LeftChar=1\r
+[Editor_21]\r
+Open=0\r
+Top=0\r
+CursorCol=1\r
+CursorRow=14\r
+TopLine=1\r
+LeftChar=1\r
+[Editor_22]\r
+Open=0\r
+Top=0\r
+CursorCol=30\r
+CursorRow=22\r
+TopLine=1\r
+LeftChar=1\r
+[Editor_23]\r
+Open=0\r
+Top=0\r
+CursorCol=22\r
+CursorRow=8\r
+TopLine=1\r
+LeftChar=1\r
+[Editor_24]\r
+Open=0\r
+Top=0\r
diff --git a/src/Amstrad.c b/src/Amstrad.c
new file mode 100644 (file)
index 0000000..26d83d2
--- /dev/null
@@ -0,0 +1,249 @@
+#include <stdio.h>\r
+#include <stdlib.h>\r
+\r
+#include <math.h>\r
+\r
+#include "UberCassette.h"\r
+#include "WAV.h"\r
+#include "Sample.h"\r
+#include "Spectrum.h"\r
+#include "Amstrad.h"\r
+\r
+#define MAX_WAVELENGTH 20000\r
+\r
+unsigned char *Amstrad_ParseWAV( unsigned char *wavData )\r
+{\r
+       unsigned char *tParsedData = NULL;\r
+       struct RAW_Format tRawData;\r
+\r
+       // First off, extract the RAW data.\r
+       tRawData = WAV_GetRAW( wavData, false );\r
+\r
+    if ( tRawData.data == NULL )\r
+        return NULL;\r
+\r
+       // First we scan the entire file for the wavelength of the header.\r
+       if ( gAlgorithmType == TRIGGER )\r
+               BuildRawWaveList( tRawData, 0, NULL, -1, true );\r
+       else \r
+               BuildRawWaveList_Cleaned( tRawData, 0, NULL, -1, true );\r
+\r
+       if ( gOutputType != CSW )\r
+               Amstrad_BuildTapeBlocks( tRawData );\r
+\r
+       return (unsigned char *)1; // We have data ... but it's somewhere else.\r
+}\r
+\r
+void Amstrad_BuildTapeBlocks( struct RAW_Format format )\r
+{\r
+#define SBTB_RETRIES 20\r
+\r
+       int tPointer = 0, tDataStartPointer;\r
+       int *tRawPointer = &gRawCycles[ tPointer ], *tDataStartRawPointer;\r
+       double *tWavePointer = &gWaveCycles[ tPointer ], *tDataStartWavePointer;\r
+       int tBlockThresholds[ 3 ]={0,0,0}, tBlockWavelengths[ NUMBER_OF_THRESHOLDS ], tValueTable[ NUMBER_OF_THRESHOLDS ], tCPUThresholds[ 3 ];\r
+       double tOffset = 0.0f, tDataStartOffset;\r
+       int tDelayCounter = 0;\r
+       int tHeaderCycles = 0;\r
+       enum Stage { SS_HEADER, SS_SYNC1, SS_SYNC2, SS_DATA } tStage = SS_HEADER;\r
+       unsigned char tData[ 128 * 1024 ];\r
+       int tDataSize = 0, tBit, tPulse;\r
+       unsigned char tXORByte = 0;\r
+       double tDivisors[ 2 ];\r
+       int tRetry = SBTB_RETRIES;\r
+       bool tDataInvalid = true;\r
+       unsigned short tDataBlockLength = 0;\r
+       struct LoaderStruct tLoader;\r
+\r
+       tDivisors[ 0 ] = gThresholdDivisor[ 0 ];\r
+       tDivisors[ 1 ] = gThresholdDivisor[ 1 ];\r
+\r
+       memset( &tLoader, 0, sizeof( struct LoaderStruct ) );\r
+       tLoader.id = LOADER_ROM; \r
+       tLoader.bitsInLastByte = 8;\r
+\r
+       while ( tPointer < gRawLength && tOffset < gRAWFormat.size && *tRawPointer > 0 && *tWavePointer > 0 )\r
+       {\r
+               // What waves are used in this block?\r
+               if ( *tRawPointer >= MAX_WAVELENGTH || BuildWavelengthTable( format, tOffset, 1, tBlockWavelengths ) == false )\r
+               {\r
+                       // Silence is golden.\r
+                       tDelayCounter += *tRawPointer++;\r
+                       tOffset += *tWavePointer++;\r
+                       tPointer++;\r
+               }\r
+               else\r
+               {\r
+                       printf( "Adding data at %f.\n", tOffset );\r
+\r
+                       if ( tDelayCounter > 0 )\r
+                       {\r
+                               if ( tDataSize )\r
+                               {\r
+                                       Spectrum_AddTurboDataBlock( format, tLoader, tDataSize, (char *)tData, tDelayCounter );\r
+                               }\r
+                               else\r
+                                       Spectrum_AddPauseBlock( format, tDelayCounter );\r
+                               tDelayCounter = 0;\r
+                       }\r
+\r
+                       tDataInvalid = true;\r
+                       tRetry = SBTB_RETRIES;\r
+                       tDataStartOffset = tOffset;\r
+                       tDataStartRawPointer = tRawPointer;\r
+                       tDataStartPointer = tPointer;\r
+                       tDataStartWavePointer = tWavePointer;\r
+\r
+               if ( tOffset == 1720361 )\r
+               {\r
+                       bool test=true;\r
+               }\r
+\r
+                       while ( tRetry > 0 && tDataInvalid )\r
+                       {\r
+                               tXORByte = 0x00;\r
+                               tDataSize = 0; tBit = 0; *tData = 0; tPulse = 0; tStage = SS_HEADER;\r
+\r
+                               // Work out our thresholds....\r
+                               BuildThresholds( format, 2, &tBlockThresholds[ 0 ], tBlockWavelengths, tValueTable );\r
+\r
+                               tCPUThresholds[ 0 ] = ConvertToCycles( tBlockThresholds[ 0 ]); tCPUThresholds[ 1 ] = ConvertToCycles( tBlockThresholds[ 1 ] ); tCPUThresholds[ 2 ] = ConvertToCycles( tBlockThresholds[ 2 ] );\r
+\r
+                               tLoader.onePulse = tCPUThresholds[ 1 ] / 2; tLoader.zeroPulse = tCPUThresholds[ 0 ] / 2;\r
+                               tLoader.pilotPulse = tLoader.onePulse; tLoader.sync1 = tLoader.zeroPulse;\r
+                               tLoader.sync2 = tLoader.zeroPulse; tLoader.pilotLength = 0;\r
+\r
+                               if ( tBlockThresholds[ 1 ] == -1 )\r
+                               {\r
+                                       while ( tPointer < gRawLength && *tRawPointer < MAX_WAVELENGTH )\r
+                                       {\r
+                                               tOffset += *tWavePointer;\r
+                                               tPointer++;\r
+                                               tRawPointer++;\r
+                                               tWavePointer++;\r
+                                       }\r
+                                       tLoader.pilotLength = 0;\r
+                                       break;\r
+                               }\r
+\r
+                               // Find our header sync length\r
+                               while ( tPointer < gRawLength && *tRawPointer < MAX_WAVELENGTH )\r
+                               {\r
+                                       if ( tStage == SS_HEADER )\r
+                                       {\r
+                                               if ( tValueTable[ *tRawPointer * 2 ] == 1 )\r
+                                               {\r
+                                                       // We're in standard header timing.\r
+                                                       tHeaderCycles++;\r
+                                                       tLoader.pilotLength++;\r
+                                               }\r
+                                               else if ( tLoader.pilotLength > 100 )\r
+                                               {\r
+                                                       tStage = SS_SYNC1;\r
+                                                       printf( "Starting data with pulse lengths %d (%ld) and %d(%ld).\n", tBlockThresholds[ 0 ], ConvertToCycles( tBlockThresholds[ 0 ] ), tBlockThresholds[ 1 ], ConvertToCycles( tBlockThresholds [ 1 ]) );\r
+\r
+                                                       continue; // Go back and check this cycle.\r
+                                               }\r
+                                       }\r
+                                       else if ( tStage == SS_SYNC1 )\r
+                                       {\r
+                                               if ( tValueTable[ *tRawPointer * 2 ] == 0 )\r
+                                               {\r
+                                                       if ( tLoader.id == LOADER_ROM )\r
+                                                               tStage = SS_SYNC2;\r
+                                               }\r
+                                               else\r
+                                               {\r
+                                                       tStage = SS_HEADER;     // Wot no sync pulses?\r
+                                                       printf(" WARNING: Invalid sync pulse.\n" );\r
+                                               }\r
+                                       }\r
+                                       else if ( tStage == SS_SYNC2 )\r
+                                       {\r
+                                               if ( tValueTable[ *tRawPointer * 2 ] == 0 )\r
+                                               {\r
+                                                       tStage = SS_DATA;\r
+                                               }\r
+                                               else\r
+                                               {\r
+                                                       tStage = SS_HEADER;     // Wot no sync pulses?\r
+                                                       printf(" WARNING: Invalid sync pulse.\n" );\r
+                                               }\r
+                                       }\r
+                                       else if ( tStage == SS_DATA )\r
+                                       {\r
+                                               if ( tPulse == 0 )\r
+                                                       tPulse = *tRawPointer;\r
+                                               else\r
+                                               {\r
+                                                       tPulse += *tRawPointer;\r
+                                                       tData[ tDataSize ] <<= 1;\r
+                                                       if ( tValueTable[ tPulse ] == 1 )\r
+                                                               tData[ tDataSize ] |= 1;\r
+                                                       else if ( tValueTable[ tPulse ] == 0 )\r
+                                                               tData[ tDataSize ] |= 0;\r
+                                                       tBit++;\r
+                                                       if ( tBit == 8 || (tDataSize == (tDataBlockLength-1) && tBit == tLoader.bitsInLastByte) )\r
+                                                       {\r
+                                                               if ( tDataSize < tDataBlockLength )\r
+                                                               {\r
+                                                                       tXORByte ^= tData[ tDataSize ];\r
+                                                               }\r
+                                                               tData[ tDataSize ] <<= (8 - tLoader.bitsInLastByte);\r
+                                                               tDataSize++;\r
+                                                               tData[ tDataSize ] = 0;\r
+                                                               tBit = 0;\r
+                                                               tDataBlockLength = 0;   // We've done all that data.\r
+                                                       }\r
+                                                       tPulse = 0;\r
+                                               }\r
+                                               tDelayCounter = 0;\r
+                                       }\r
+\r
+                                       tOffset += *tWavePointer;\r
+                                       tPointer++;\r
+                                       tRawPointer++;\r
+                                       tWavePointer++;\r
+                               }\r
+                               if ( tData[ 0 ] == 0x00 )\r
+                               {\r
+                                       // This is a header.\r
+                                       tDataBlockLength = tData[ 11 ] + tData[ 12 ] * 256;\r
+                               }\r
+                               if ( tLoader.id == LOADER_ROM )\r
+                               {\r
+                                       if ( 0 )\r
+                                       {\r
+                                               printf(" WARNING! Invalid XOR checksum.\n" );\r
+               \r
+                                               if ( --tRetry )\r
+                                               {\r
+                                                       double tThresholdMod;\r
+                                                       printf(" Retrying...\n" );\r
+                                                       tThresholdMod = 0.025f * (float)((SBTB_RETRIES - (tRetry - 1) ) / 2) * ( (tRetry & 1) ? +1 : -1 );\r
+                                                       gThresholdDivisor[ 0 ] = tDivisors[ 0 ] + tThresholdMod;\r
+                                                       gThresholdDivisor[ 1 ] = tDivisors[ 1 ] + tThresholdMod;\r
+                                                       tOffset = tDataStartOffset;\r
+                                                       tRawPointer = tDataStartRawPointer ;\r
+                                                       tPointer = tDataStartPointer;\r
+                                                       tWavePointer = tDataStartWavePointer;\r
+                                               }\r
+                                               else\r
+                                                       printf( "Giving up.\n" );\r
+                                       }\r
+                                       else\r
+                                               tDataInvalid = false;\r
+                               }\r
+                               else\r
+                                       tDataInvalid = false;\r
+                       }\r
+               }\r
+       }\r
+       if ( tDataSize )\r
+       {\r
+               Spectrum_AddTurboDataBlock( format, tLoader, tDataSize, (char *)tData, tDelayCounter );\r
+       }\r
+\r
+       gThresholdDivisor[ 0 ] = tDivisors[ 0 ];\r
+       gThresholdDivisor[ 1 ] = tDivisors[ 1 ];\r
+}\r
diff --git a/src/Amstrad.h b/src/Amstrad.h
new file mode 100644 (file)
index 0000000..f862209
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef __AMSTRAD_H__\r
+#define __AMSTRAD_H__\r
+\r
+unsigned char *Amstrad_ParseWAV( unsigned char *wavData );\r
+void Amstrad_BuildTapeBlocks( struct RAW_Format format );\r
+\r
+#endif\r
diff --git a/src/CBM.c b/src/CBM.c
new file mode 100644 (file)
index 0000000..763fac0
--- /dev/null
+++ b/src/CBM.c
@@ -0,0 +1,356 @@
+/* Handler for CBM tapes. */\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+\r
+#include <math.h>\r
+\r
+#include "UberCassette.h"\r
+#include "WAV.h"\r
+#include "Sample.h"\r
+#include "CBM.h"\r
+\r
+// Normal CBM tapes measure pulse length on crossing the zero boundary from + to -.\r
+\r
+void CBM_BuildTapeBlocks( struct RAW_Format format );\r
+struct CBM_CassetteBlock *CBM_FindTapeBlock( struct RAW_Format format, double *pointer );\r
+\r
+\r
+struct CBM_CassetteBlock *gCBM_CassetteBlockList = NULL;\r
+const float cMinimumCurveGradient = 0.02f;\r
+\r
+\r
+\r
+unsigned char *CBM_ParseWAV( unsigned char *wavData )\r
+{\r
+       unsigned char *tParsedData = NULL;\r
+       struct RAW_Format tRawData;\r
+\r
+       // First off, extract the RAW data.\r
+       tRawData = WAV_GetRAW( wavData, false );\r
+\r
+    if ( tRawData.data == NULL )\r
+        return NULL;\r
+\r
+       // First we scan the entire file for the wavelength of the header.\r
+    printf( "Building wavelength table.\n" );\r
+       BuildWavelengthTable( tRawData, 0, -1, gWaveLengthTable );\r
+\r
+       // Work out our thresholds....\r
+    printf( "Building thresholds.\n" );\r
+       BuildThresholds( tRawData, 3, &gThresholds[ 0 ], gWaveLengthTable, gSample_ValueTable );\r
+\r
+       if ( gOutputType == TAP || gOutputType == WAV )\r
+       {\r
+               if ( gAlgorithmType == TRIGGER )\r
+                       BuildRawWaveList( tRawData, 0, NULL, -1, false );\r
+               else \r
+                       BuildRawWaveList_Cleaned( tRawData, 0, NULL, -1, false );\r
+               return (unsigned char *)1; // We have data ... but it's somewhere else.\r
+       }\r
+\r
+       // Now we have lovely 8-bit mono raw data.\r
+       CBM_BuildTapeBlocks( tRawData );\r
+\r
+       return tParsedData;\r
+}\r
+\r
+\r
+void CBM_BuildTapeBlocks( struct RAW_Format format )\r
+{\r
+       struct CBM_CassetteBlock *tBlock, *tLastBlock;\r
+       double tPointer = 1;\r
+\r
+       gCBM_CassetteBlockList = NULL;\r
+\r
+       // Now we look for our data.\r
+       while ( tPointer && (tBlock = CBM_FindTapeBlock( format, &tPointer )) > 0 )\r
+       {\r
+               if ( gCBM_CassetteBlockList == NULL )\r
+               {\r
+                       gCBM_CassetteBlockList = (struct CBM_CassetteBlock *)malloc( sizeof( struct CBM_CassetteBlock ) );\r
+                       *gCBM_CassetteBlockList = *tBlock;\r
+                       gCBM_CassetteBlockList->next = NULL;\r
+                       tLastBlock = gCBM_CassetteBlockList;\r
+               }\r
+               else\r
+               {\r
+                       tLastBlock->next = (struct CBM_CassetteBlock *)malloc( sizeof( struct CBM_CassetteBlock ) );\r
+                       tLastBlock = tLastBlock->next;\r
+                       *tLastBlock = *tBlock;\r
+                       tLastBlock->next = NULL;\r
+               }\r
+       }\r
+}\r
+\r
+void CBM_ReadData( unsigned char *data, int length, struct RAW_Format format, double *pointer )\r
+{\r
+       double tPointer = *pointer;\r
+       bool tValidWave = true, tDoneSync = true;\r
+       double tWaveLength;\r
+       unsigned char tLastByte = 0, tChecksum = 0;\r
+       int tBytes = 0, tBits = 0, tCycle = 0, tLastCycle = 0, tParity = 0, tBlockNumber = 0;\r
+       unsigned char *tData[ 2 ];\r
+       int tLoggedByte = 0;\r
+\r
+       tData[ 0 ] = (unsigned char *)malloc( length );\r
+       tData[ 1 ] = (unsigned char *)malloc( length );\r
+\r
+       while ( tBlockNumber < 2 )\r
+       {\r
+               tPointer = CBM_FindHeader( format, tPointer );\r
+               tBytes = -9;\r
+\r
+               if ( tPointer == 0 )\r
+               {\r
+                       *pointer = 0;\r
+                       free( tData[ 0 ] );\r
+                       free( tData[ 1 ] );\r
+                       return;\r
+               }\r
+               //printf( "\nReading block at %ld.\n", tPointer );\r
+\r
+//             printf( "0000:  " );\r
+\r
+               tCycle = 0; tDoneSync = true; tBits = 0; tParity = 0; tChecksum = 0; tLastByte = 0; tLoggedByte = 0;\r
+\r
+               while ( tValidWave && tBytes < length )\r
+               {\r
+                       tChecksum = 0;\r
+                       tWaveLength = FindWavelength( format, &tPointer, false, false, false, NULL );\r
+\r
+                       if ( gSample_ValueTable[ (int)tWaveLength ] != -1 )\r
+                       {\r
+                               if ( gSample_ValueTable[ (int)tWaveLength ] == 2 )\r
+                               {\r
+                                       //printf( "Sync byte %d at %d.   ", tBytes, tPointer );\r
+                                       if ( tBits < 8 && tBits != 0 )\r
+                                       {\r
+                                               //printf( "*** ERROR *** Sync byte out of place.\n" );\r
+                                       }\r
+                                       tLastByte = 0;\r
+                                       tBits = 0;\r
+                                       tParity = 0;\r
+                                       tDoneSync = true;\r
+                                       tCycle = 0;\r
+                                       //printf( "         %04x:  ", tBytes );\r
+                               }\r
+                               else if ( tDoneSync == true )\r
+                               {\r
+                                       tDoneSync = false;\r
+                               }\r
+                               else\r
+                               {\r
+                                       if ( tCycle == 0 )\r
+                                       {\r
+                                               tLastCycle = gSample_ValueTable[ (int)tWaveLength ];\r
+       //                                      if ( tBits < 8 )\r
+       //                                              printf( "%d", tLastCycle );\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                               if ( tBits == 8 )\r
+                                               {\r
+       //                                              printf( " = %02x   ", tLastByte );\r
+                                                       // Check parity!\r
+                                                       if ( tLastCycle == 0 )\r
+                                                       {\r
+                                                               if ( gSample_ValueTable[ (int)tWaveLength ] == 1 )\r
+                                                               {\r
+                                                                       if ( tParity == 0 )\r
+                                                                               ;//printf( "\n*** Parity error on byte %ld ***.\n", tPointer );\r
+                                                               }\r
+                                                       }\r
+                                                       else\r
+                                                       {\r
+                                                               if ( gSample_ValueTable[ (int)tWaveLength ] == 0  )\r
+                                                               {\r
+                                                                       if ( tParity == 1 )\r
+                                                                               ;//printf( "\n*** Parity error on byte %ld ***.\n", tPointer );\r
+                                                               }\r
+                                                       }\r
+\r
+                                                       if ( tBytes >= 0 )\r
+                                                       {\r
+                                                               tData[ tBlockNumber ][ tBytes ] = tLastByte;\r
+/*                                                             if ( tBytes < 256 )\r
+                                                               {\r
+                                                                       printf( " %02x", tLastByte );\r
+                                                                       tLoggedByte++;\r
+                                                                       if ( tLoggedByte == 16 )\r
+                                                                       {\r
+                                                                               printf( "\n%04x:  ", tBytes+1 );\r
+                                                                               tLoggedByte = 0;                                                                \r
+                                                                       }\r
+                                                               }*/\r
+                                                               tChecksum ^= tLastByte;\r
+                                                       }\r
+                                                       tBytes++;\r
+                                                       tBits = 9;\r
+                                               }\r
+                                               else\r
+                                               {\r
+       //                                              printf( "%d", gSample_ValueTable[ tWaveLength ] );\r
+\r
+                                                       if ( tLastCycle == 0 )\r
+                                                       {\r
+                                                               if ( gSample_ValueTable[ (int)tWaveLength ] == 1 )\r
+                                                                       tLastByte |= 0;\r
+                                                               else\r
+                                                               {\r
+                                                                       //printf( "*** ERROR *** found two short cycles." );\r
+                                                               }\r
+                                                       }\r
+                                                       else\r
+                                                       {\r
+                                                               if ( gSample_ValueTable[ (int)tWaveLength ] == 0 )\r
+                                                               {\r
+                                                                       tLastByte |= 1 << tBits;\r
+                                                                       tParity = 1 - tParity;\r
+                                                               }\r
+                                                               else\r
+                                                               {\r
+                                                                       //printf( "*** ERROR *** found two medium cycles." );\r
+                                                               }\r
+                                                       }\r
+                                                       tBits++;\r
+                                                       if ( tBits > 8 )\r
+                                                       {\r
+                                                               //printf( "*** ERROR *** long byte.\n" );\r
+                                                       }\r
+                                               }       \r
+                                       }\r
+                                       //printf( "%d", gSample_ValueTable[ tWaveLength ] );\r
+                                       tCycle = 1 - tCycle;\r
+                               }\r
+                       }\r
+                       else\r
+                               tValidWave = false;\r
+               }\r
+\r
+               if ( tValidWave == false )\r
+                       break;\r
+\r
+               tBlockNumber++;\r
+               tLastCycle = 0;\r
+       }\r
+\r
+       for ( tBytes = 0 ; tBytes < length ; tBytes++ )\r
+       {\r
+               if ( tData[ 0 ][ tBytes ] != tData[ 1 ][ tBytes ] )\r
+                       ;//printf( "Data error on byte %d: is %02x and %02x.\n", tBytes, tData[ 0 ][ tBytes ], tData[ 1 ][ tBytes ] );\r
+\r
+               data[ tBytes ] = tData[ 0 ][ tBytes ];          \r
+       }\r
+\r
+       free( tData[ 0 ] );\r
+       free( tData[ 1 ] );\r
+\r
+       // Skip the trailing zeroes.\r
+       tPointer = CBM_FindHeader( format, tPointer);\r
+\r
+       *pointer = tPointer;\r
+}\r
+\r
+\r
+struct CBMHeader CBM_ReadHeader( struct RAW_Format format, double *pointer )\r
+{\r
+       struct CBMHeader tHeader;\r
+       unsigned char tData[ 192 ];\r
+       int i;\r
+\r
+//     printf( "\n %04x:  ", tBytes );\r
+\r
+       CBM_ReadData( &tData[ 0 ], 192, format, pointer );\r
+\r
+       if ( *pointer == 0 )\r
+       {\r
+               tHeader.startAddress = tHeader.endAddress = 0;\r
+               return tHeader;\r
+       }\r
+       tHeader.startAddress = tData[ 0x01 ] + tData[ 0x02 ] * 0x0100;\r
+       tHeader.endAddress = tData[ 0x03 ] + tData[ 0x04 ] * 0x0100;\r
+       for ( i=0 ; i < 16 ; i++ )\r
+               tHeader.name[ i ] = tData[ 0x05 + i ];\r
+\r
+       printf( "Found header for block %16s, start address is 0x%04x, length is 0x%04x.\n", tHeader.name, tHeader.startAddress, tHeader.endAddress - tHeader.startAddress + 1 );\r
+\r
+       return tHeader; \r
+}\r
+\r
+struct CBM_CassetteBlock *CBM_FindTapeBlock( struct RAW_Format format, double *pointer )\r
+{\r
+       double tPointer = *pointer;\r
+       struct CBM_CassetteBlock *tBlock = NULL;\r
+       struct CBMHeader tHeader;\r
+       int i;\r
+\r
+       // We have a header! Do stuff!\r
+       tBlock = (struct CBM_CassetteBlock *)malloc( sizeof( struct CBM_CassetteBlock ) );\r
+       tHeader = CBM_ReadHeader( format, &tPointer );\r
+       if ( tPointer == 0 )\r
+               return NULL;\r
+       tBlock->startAddress = CorrectEndianShort( tHeader.startAddress );\r
+       tBlock->endAddress = CorrectEndianShort( tHeader.endAddress );\r
+       tBlock->c64sFileType = 0x01;\r
+       tBlock->cbm1541FileType = 0x82;\r
+\r
+       for ( i=0 ; i<16 ; i++ )\r
+               tBlock->filename[ i ] = tHeader.name[ i ];\r
+\r
+       tBlock->data = (unsigned char *)malloc( tBlock->endAddress - tBlock->startAddress + 1 );\r
+       CBM_ReadData( tBlock->data, tBlock->endAddress - tBlock->startAddress + 1, format, &tPointer );\r
+\r
+       *pointer = tPointer;\r
+       return tBlock;\r
+}\r
+\r
+double CBM_FindHeader( struct RAW_Format format, double pointer )\r
+{\r
+       double tPointer = pointer;\r
+       bool tNoHeader = true;\r
+       int tZeroCounter = 0;\r
+       double tWaveLength = 0;\r
+\r
+       while ( tNoHeader )\r
+       {\r
+               tPointer = FindNextWavelengthStart( format, tPointer );\r
+\r
+               if ( tPointer == -1 )\r
+                       return 0;       // No headers here, move along please.\r
+\r
+               // Find a valid blip.\r
+               tWaveLength = FindWavelength( format, &tPointer, false, false, false, NULL );\r
+               AddWave( NULL, 1, tWaveLength );\r
+\r
+               if ( tPointer == -1 )\r
+                       return 0;       // No headers here, move along please.\r
+\r
+               if ( tWaveLength == 0 || gSample_ValueTable[ (int)tWaveLength ] != 0 )\r
+                       continue;       // Not a header wave after all. Darn it.\r
+\r
+               // We've got a zero!\r
+               tZeroCounter = 0;\r
+               while ( gSample_ValueTable[ (int)tWaveLength ] == 0 && tPointer < format.size )\r
+               {\r
+                       tZeroCounter++;\r
+                       tPointer++;\r
+\r
+                       if ( tPointer == format.size )\r
+                               return 0;\r
+\r
+                       tWaveLength = FindWavelength( format, &tPointer, false, false, false, NULL );\r
+//                     printf( " %d ", tPointer );\r
+               }\r
+\r
+               if ( tZeroCounter >= gHeaderCheckSize )\r
+               {\r
+                       tNoHeader = false;\r
+               }\r
+       }\r
+\r
+       // We have found a header!\r
+\r
+       return tPointer;\r
+}\r
+\r
diff --git a/src/CBM.h b/src/CBM.h
new file mode 100644 (file)
index 0000000..1c34bd4
--- /dev/null
+++ b/src/CBM.h
@@ -0,0 +1,27 @@
+/* The WAV handler for CBM tapes. */\r
+\r
+#include "WAV.h"\r
+\r
+struct CBM_CassetteBlock\r
+{\r
+       unsigned char c64sFileType;\r
+       unsigned char cbm1541FileType;\r
+       unsigned short startAddress;\r
+       unsigned short endAddress;\r
+       unsigned char filename[ 128 ];\r
+       unsigned long offset;\r
+       unsigned char *data;\r
+       struct CBM_CassetteBlock *next;\r
+};\r
+\r
+struct CBMHeader\r
+{\r
+       unsigned short startAddress;\r
+       unsigned short endAddress;\r
+       char name[ 128 ];\r
+};\r
+\r
+extern struct CBM_CassetteBlock *gCBM_CassetteBlockList;\r
+\r
+unsigned char *CBM_ParseWAV( unsigned char *rawData );\r
+double CBM_FindHeader( struct RAW_Format format, double pointer );\r
diff --git a/src/CSW.c b/src/CSW.c
new file mode 100644 (file)
index 0000000..6866b4b
--- /dev/null
+++ b/src/CSW.c
@@ -0,0 +1,143 @@
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+\r
+#include "UberCassette.h"\r
+#include "Sample.h"\r
+\r
+#include "Spectrum.h"\r
+#include "CBM.h"\r
+#include "CSW.h"\r
+\r
+#define SAMPLE_RATE (44100)\r
+\r
+struct CSW_CSWInfo\r
+{\r
+       char identifier[ 23 ];\r
+       unsigned char majorRevision;\r
+       unsigned char minorRevision;\r
+       unsigned char sampleRate[ 4 ];\r
+       unsigned char pulses[ 4 ];\r
+       unsigned char compression;\r
+       unsigned char flags;\r
+       unsigned char header;\r
+       char encoder[ 16 ];\r
+};\r
+\r
+void CSW_WriteHeader( FILE *file, unsigned long pulses )\r
+{\r
+       struct CSW_CSWInfo tCSWInfo;\r
+       int tByteLength = 0;\r
+       unsigned long tPointer = 0;\r
+\r
+       sprintf( tCSWInfo.identifier, "Compressed Square Wave%c", 0x1A );\r
+       tCSWInfo.majorRevision = 2;\r
+       tCSWInfo.minorRevision = 0;\r
+       *((unsigned long *)&tCSWInfo.sampleRate[ 0 ]) = CorrectEndianLong( SAMPLE_RATE );\r
+       *((unsigned long *)&tCSWInfo.pulses[ 0 ]) = CorrectEndianLong( pulses );\r
+       tCSWInfo.compression = 1;\r
+       tCSWInfo.flags = 0;\r
+       tCSWInfo.header = 0;\r
+       sprintf( tCSWInfo.encoder, "UberCassette" );\r
+\r
+       fwrite( &tCSWInfo, sizeof( struct CSW_CSWInfo ), 1, file );\r
+}\r
+\r
+void CSW_WriteBlocks( FILE *file, int *data, unsigned long length )\r
+{\r
+       unsigned long tPointer = 0;\r
+       unsigned long tCycles;\r
+       int tDataLength = 0;\r
+       //signed char tDistances[ 3 ];\r
+       unsigned char *tBuffer;\r
+\r
+       tBuffer = (unsigned char *)malloc( 10 * 1024 * 1024 );\r
+       if (tBuffer == NULL )\r
+       {\r
+               printf( "Couldn't allocate CSW workspace.\n" );\r
+               return;\r
+       }\r
+       while ( tPointer < length )\r
+       {\r
+               tCycles = (unsigned long)(ConvertFromCyclesToSeconds( data[ tPointer ] ) * (float)SAMPLE_RATE);\r
+               if ( tCycles > 0xFF )\r
+               {\r
+                       tBuffer[ tDataLength++ ] = 0x00;\r
+                       tBuffer[ tDataLength++ ]= tCycles & 0xFF;\r
+                       tBuffer[ tDataLength++ ]= (unsigned char )((tCycles & 0xFF00) >> 8);\r
+                       tBuffer[ tDataLength++ ]= (unsigned char )((tCycles & 0xFF0000) >> 16);\r
+                       tBuffer[ tDataLength++ ]= (unsigned char )((tCycles & 0xFF000000) >> 24);\r
+               }\r
+               else\r
+               {\r
+                       tBuffer[ tDataLength++ ] = (unsigned char )tCycles;\r
+               }\r
+               tPointer++;\r
+       }\r
+\r
+       CSW_WriteHeader( file, length );\r
+       fwrite( tBuffer, tDataLength, 1, file );\r
+\r
+       free( tBuffer );\r
+}\r
+\r
+void CSW_Output( struct Spectrum_CassetteBlock *list, char *filename )\r
+{\r
+       FILE *tOutputFile = NULL;\r
+       struct Spectrum_CassetteBlock *tBlock = list;\r
+\r
+       unsigned long tLength = gRawLength;\r
+\r
+    printf( "Writing CSW file.\n" );\r
+\r
+       tOutputFile = fopen( filename, "wb" );\r
+       if ( tOutputFile == NULL )\r
+       {\r
+               printf( "Couldn't open output file.\n" );\r
+               return;\r
+       }\r
+\r
+       CSW_WriteBlocks( tOutputFile, gRawCycles, tLength );                    \r
+\r
+       fclose( tOutputFile );\r
+       \r
+       printf( "Written CSW file.\n" );\r
+}\r
+\r
+unsigned char *CSW_Parse( unsigned char *data, int size )\r
+{\r
+       int tIndex = 0;\r
+       unsigned char *tPointer = data;\r
+       struct CSW_CSWInfo *tInfo;\r
+       unsigned long tSampleRate;\r
+\r
+       tInfo = (struct CSW_CSWInfo *)data;\r
+       tIndex = sizeof( struct CSW_CSWInfo );\r
+       tPointer = &data[ tIndex ];\r
+\r
+       tSampleRate = tInfo->sampleRate[ 0 ] + (tInfo->sampleRate[ 1 ] << 8) + (tInfo->sampleRate[ 2 ] << 16) + (tInfo->sampleRate[ 3 ] << 24);\r
+       gWAVFormat.sampleRate = tSampleRate;\r
+\r
+       for ( tIndex = 0 ; tIndex < size ; tIndex++ )\r
+       {\r
+               if ( *tPointer == 0x00 )\r
+               {\r
+                       int tDelay = 0x00000000;\r
+\r
+                       tDelay = *(tPointer+1);\r
+                       tDelay += *(tPointer+2) << 8;\r
+                       tDelay += *(tPointer+3) << 16;\r
+                       tDelay += *(tPointer+4) << 24;\r
+                       tPointer += 4;\r
+\r
+                       AddRawCycle( (float)tDelay );\r
+               }\r
+               else\r
+               {\r
+                       AddRawCycle( (float)*tPointer );        \r
+               }\r
+\r
+               tPointer++;\r
+       }\r
+       return (unsigned char *)1;\r
+}\r
diff --git a/src/CSW.h b/src/CSW.h
new file mode 100644 (file)
index 0000000..5724e86
--- /dev/null
+++ b/src/CSW.h
@@ -0,0 +1,2 @@
+void CSW_Output( struct Spectrum_CassetteBlock *list, char *filename );\r
+unsigned char *CSW_Parse( unsigned char *data, int size );\r
diff --git a/src/Machines.h b/src/Machines.h
new file mode 100644 (file)
index 0000000..49361c9
--- /dev/null
@@ -0,0 +1,90 @@
+const struct MachineData MACHINE_VIC=\r
+{\r
+       "C64",\r
+       1,\r
+       VIC20,\r
+       1108405,\r
+       1022727,\r
+       false,\r
+       false,\r
+       {0.75f, 0.75f},\r
+       ConvertToCycles,\r
+};\r
+\r
+const struct MachineData MACHINE_C16=\r
+{\r
+       "C16",\r
+       2,\r
+       C16,\r
+       886724,\r
+       894886,\r
+       false,\r
+       false,\r
+       {0.75f, 0.75f},\r
+       ConvertToCycles,\r
+};\r
+\r
+const struct MachineData MACHINE_C64=\r
+{\r
+       "C64",\r
+       0,\r
+       C64,\r
+       985248,\r
+       1022727,\r
+       false,\r
+       false,\r
+       {0.75f, 0.75f},\r
+       ConvertToCycles,\r
+};\r
+\r
+const struct MachineData MACHINE_BBC=\r
+{\r
+       "BBC",\r
+       0,\r
+       BBC,\r
+       2000000,\r
+       2000000,\r
+       false,\r
+       true,\r
+       {0.6f, 0.5f},\r
+       ConvertToCycles,\r
+};\r
+\r
+const struct MachineData MACHINE_ELECTRON=\r
+{\r
+       "ELECTRON",\r
+       0,\r
+       ELECTRON,\r
+       2000000,\r
+       2000000,\r
+       false,\r
+       true,\r
+       {0.6f, 0.5f},\r
+       ConvertToCycles,\r
+};\r
+\r
+const struct MachineData MACHINE_SPECTRUM=\r
+{\r
+       "SPECTRUM",\r
+       0,\r
+       SPECTRUM,\r
+       3500000,\r
+       3500000,\r
+       true,\r
+       true,\r
+       {0.5f, 0.5f},\r
+       ConvertToCycles,\r
+};\r
+\r
+const struct MachineData MACHINE_AMSTRAD=\r
+{\r
+       "AMSTRAD",\r
+       0,\r
+       AMSTRAD,\r
+       3500000,        /* TZX always uses 3.5MHz. */\r
+       3500000,\r
+       true,\r
+       true,\r
+       {0.5f, 0.5f},\r
+       ConvertToCycles,\r
+};\r
diff --git a/src/Makefile b/src/Makefile
new file mode 100644 (file)
index 0000000..1f0997b
--- /dev/null
@@ -0,0 +1,35 @@
+CC = gcc
+LD = gcc
+
+CFLAGS = -D LINUX -g -c 
+CFLAGS += -D_DEBUG -DDUMP_RAW
+LDFLAGS = -Wl,-Map -Xlinker linkermap
+LIBS = -lm
+STRIP = strip --strip-unneeded --remove-section .comment
+
+OBJS = Amstrad.o Acorn.o CBM.o main.o Sample.o T64.o TAP.o UEF.o WAV.o CSW.o TZX.o Spectrum.o
+
+all:   ubercassette
+
+clean:
+       rm *.o
+       rm ubercassette
+
+ubercassette:  $(OBJS)
+               $(LD) $(LDFLAGS) $^ $(LIBS) -o $@
+               cp ubercassette ../
+
+main.o: main.c UberCassette.h
+Sample.o: Sample.c Sample.h WAV.h UberCassette.h
+
+Acorn.o: Acorn.c Acorn.h UberCassette.h WAV.h Sample.h
+CBM.o: CBM.c CBM.h UberCassette.h WAV.h Sample.h
+Spectrum.o: Spectrum.c WAV.h UberCassette.h CSW.h TZX.h
+Amstrad.o: Amstrad.c WAV.h UberCassette.h TZX.h Spectrum.h
+
+T64.o: T64.c T64.h UberCassette.h CBM.h
+TAP.o: TAP.c TAP.h UberCassette.h CBM.h
+UEF.o: UEF.c UEF.h UberCassette.h WAV.h Acorn.h
+WAV.o: WAV.c WAV.h UberCassette.h
+CSW.o: CSW.c UberCassette.h CSW.h
+TZX.o: TZX.c TZX.h UberCassette.h
\ No newline at end of file
diff --git a/src/Sample.c b/src/Sample.c
new file mode 100644 (file)
index 0000000..0efe61f
--- /dev/null
@@ -0,0 +1,773 @@
+// Tool functions for getting the data ready to parse (if necessary).\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <math.h>\r
+\r
+#include "UberCassette.h"\r
+#include "Sample.h"\r
+#include "WAV.h"\r
+\r
+\r
+#define SAMPLE_ENTRIES 20\r
+\r
+void BuildRawWaveList( struct RAW_Format format, unsigned long offset, double *wavelengthTable, int blocks, bool halfWaves )\r
+{\r
+       double tPointer = offset, tWaveStart;\r
+       bool tFirstWave = true;\r
+       int tBlocks = blocks;\r
+\r
+       tWaveStart = tPointer;\r
+       tPointer = FindNextWavelengthStart( format, tPointer );\r
+       AddRawCycle( (double) tPointer - tWaveStart );\r
+\r
+    printf( "Building RAW Wave list.\n" );\r
+\r
+       while ( tBlocks != 0 && tPointer < format.size )\r
+       {\r
+               if ( FindWavelength( format, &tPointer, tFirstWave, false, halfWaves, wavelengthTable ) > 2000.0f )\r
+                       tBlocks--;\r
+\r
+               tFirstWave = !tFirstWave;\r
+       }\r
+       printf( "RAW Wave list done.\n" );\r
+}\r
+\r
+double FindNextWavelengthStart( struct RAW_Format format, double pointer )\r
+{\r
+       // Find the beginning of a waveform.\r
+       unsigned long tPointer = (unsigned long)pointer;\r
+\r
+       while ( format.data[ tPointer ] < gPreferences.minimumSignalLevel && tPointer < format.size )\r
+               tPointer++;\r
+\r
+       if ( tPointer == format.size )\r
+               return -1;      // No more waveforms here.\r
+\r
+       while ( format.data[ tPointer ] > 0 && tPointer < format.size )\r
+               tPointer++;\r
+\r
+       if ( tPointer == format.size )\r
+               return -1;      // Still no more waveforms.\r
+\r
+       return (double)tPointer;\r
+}\r
+\r
+\r
+void AddCurveSample( signed char *curve, unsigned char sample )\r
+{\r
+       int i;\r
+\r
+       for ( i = 0 ; i < SAMPLE_ENTRIES-1 ; i++ )\r
+               curve[ i ] = curve[ i + 1 ];\r
+       curve[ i ] = sample;\r
+}\r
+\r
+signed char GetCurveAverage( signed char *curve )\r
+{\r
+       signed char tAverage;\r
+       tAverage = ((int)curve[ SAMPLE_ENTRIES-5 ] + (int)curve[ SAMPLE_ENTRIES-4 ] + (int)curve[ SAMPLE_ENTRIES-3 ] + (int)curve[ SAMPLE_ENTRIES-2 ] + (int)curve[ SAMPLE_ENTRIES-1 ]) / 5;\r
+       return tAverage;\r
+}\r
+\r
+signed char GetCurvePeak( signed char *curve )\r
+{\r
+       signed char tPeak=0;\r
+       int i;\r
+\r
+       for ( i=0 ; i<SAMPLE_ENTRIES ; i++ )\r
+       {\r
+               if ( tPeak < curve[ i ] )\r
+                       tPeak = curve[ i ];\r
+       }\r
+       return tPeak;\r
+}\r
+\r
+signed char GetCurveTrough( signed char *curve )\r
+{\r
+       signed char tTrough=0;\r
+       int i;\r
+\r
+       for ( i=0 ; i<SAMPLE_ENTRIES ; i++ )\r
+       {\r
+               if ( tTrough > curve[ i ] )\r
+                       tTrough = curve[ i ];\r
+       }\r
+       return tTrough;\r
+}\r
+\r
+int HasStartedCurve( signed char *curve )\r
+{\r
+       signed char tTrough = GetCurveTrough( curve );\r
+\r
+       if ( tTrough > -gPreferences.minimumSignalLevel )\r
+               return false;\r
+\r
+       if ( curve[ SAMPLE_ENTRIES-1 ] > curve[ SAMPLE_ENTRIES-2 ] )\r
+               return false;   // We're going up-hill.\r
+\r
+       return true;\r
+}\r
+\r
+void AddWave( double *list, int amount, double cycles )\r
+{\r
+       int tCounter = 0;\r
+       double *tListCounter;\r
+\r
+       for ( tCounter = 0 ; tCounter < amount ; tCounter++ )\r
+       {\r
+               if ( list )\r
+               {\r
+                       tListCounter = &list[ 0 ];\r
+                       *tListCounter += 1.0f;\r
+                       list[ (int)*tListCounter ] = cycles;\r
+\r
+                       if ( cycles > 24 && cycles < 36 )\r
+                       {\r
+                               bool test=true;\r
+                       }\r
+               }\r
+               else\r
+                       AddRawCycle( cycles );\r
+\r
+               if ( cycles < 0.0f )\r
+               {\r
+                       printf( "ERROR in amount of cycles.\n" );\r
+               }\r
+               if ( cycles > 1000 )\r
+               {\r
+                       bool test=true;\r
+               }\r
+       }\r
+}\r
+\r
+void TriggerWaveAddition( struct RAW_Format format, double *wavelengthTable, bool halfWaves, double *peak, double *trough, double *waveLength, unsigned long *pointer, double *curveStart, double *lastWave, double *curveEnd, bool *loggedWave )\r
+{\r
+       double tOldTrough = 0.0f, tPeak = *peak, tTrough = *trough, tCurveStart = *curveStart, tLastWave = *lastWave, tCurveEnd = *curveEnd;\r
+       bool tLoggedWave = *loggedWave;\r
+       double tWaveLength = *waveLength;\r
+       unsigned long tPointer = *pointer;\r
+       double tCurveHalf = 0.0f;\r
+       double tTargetAmplitude, tHalfWaveLength = 0.0f;\r
+       double tClosestPoint, tClosestHalfPoint;                \r
+       double tStartOfCycle = tCurveStart;\r
+       int tTroughAmplitude=0, tPeakAmplitude=0, tOldTroughAmplitude=0;\r
+       static int tCounter = 0;        \r
+       bool tEnableCounter = false;\r
+\r
+       if ( tPointer > 1708089 )\r
+       {\r
+               tEnableCounter = true;  \r
+       }\r
+\r
+       tOldTrough = tTrough;\r
+       tTrough = tPointer - 1;\r
+\r
+       if ( tTrough && tPeak )\r
+       {\r
+               tTroughAmplitude = format.data[ (int)tTrough ]; tPeakAmplitude = format.data[ (int)tPeak ];                                     \r
+               if ( tOldTrough )\r
+                       tOldTroughAmplitude = format.data[ (int)tOldTrough ];\r
+       }\r
+\r
+       // Use this if we don't have a full wave's data.\r
+       if ( tOldTrough )\r
+               tWaveLength = (double)(tPointer - tOldTrough);\r
+\r
+       if ( tPeak && tTrough )\r
+       {\r
+               if ( gAlgorithmType == SAW )\r
+               {\r
+                       if ( halfWaves )\r
+                       {\r
+                               tCurveHalf = tOldTrough + (tPeak - tOldTrough) / 2.0f;\r
+                               tHalfWaveLength = tCurveHalf - tStartOfCycle;\r
+                               tCurveStart = tPeak + (tTrough - tPeak) / 2.0f;\r
+                       }\r
+               }\r
+               else\r
+               {\r
+                       int i;\r
+                       int tX1, tX2;\r
+                       double tGradient, tTargetY;\r
+                       tTargetAmplitude = (tPeakAmplitude + tTroughAmplitude) / 2.0f;\r
+                       tClosestPoint = tTrough;\r
+                       for ( i = (int)tPeak ; i < (int)tTrough ; i++ )\r
+                       {\r
+                               if ( fabs( (double)format.data[ i ] - tTargetAmplitude ) < fabs((double)format.data[ (int)tClosestPoint ] - tTargetAmplitude))\r
+                                       tClosestPoint = (double) i;\r
+                       }\r
+                       if ( tOldTrough && halfWaves )\r
+                       {\r
+                               tClosestHalfPoint = (double)tPeak;\r
+                               for ( i = (int)tPeak ; i > (int)tOldTrough ; i-- )\r
+                               {\r
+                                       if ( fabs( (double)format.data[ i ] - tTargetAmplitude ) < (double)format.data[ (int)tClosestHalfPoint ]- tTargetAmplitude )\r
+                                               tClosestHalfPoint = (double) i;\r
+                               }\r
+                       }\r
+                       \r
+                       // Extrapolate the actual curve trigger.\r
+                       if ( format.data[ (int)tClosestPoint ] > tTargetAmplitude )\r
+                       {\r
+                               tX1 = (int)tClosestPoint; tX2 = (int)tClosestPoint+1;\r
+                       }\r
+                       else\r
+                       {\r
+                               tX1 = (int)tClosestPoint-1; tX2 = (int)tClosestPoint;\r
+                       }\r
+\r
+                       // y = mx + c, right? So....\r
+                       tTargetY = tTargetAmplitude - (double)format.data[ (int)tX1 ];\r
+                       tGradient = (double)format.data[ tX1 ] - (double)format.data[ tX2 ];\r
+                       if (tGradient == 0.0f )\r
+                               tClosestPoint = (double)tX1 + 0.5f;\r
+                       else\r
+                               tClosestPoint = tX1 - tTargetY / tGradient;     \r
+                       tCurveStart = tClosestPoint;    // Set the end of the curve, beginning of the next.\r
+                       if ( tCurveStart > tPointer )\r
+                       {\r
+                               printf( "** WARNING ** Invalid curve length.\n" );\r
+                       }\r
+\r
+                       if ( halfWaves )\r
+                       {\r
+                               // Extrapolate the actual curve trigger.\r
+                               if ( format.data[ (int)tClosestHalfPoint ] > tTargetAmplitude )\r
+                               {\r
+                                       tX1 = (int)tClosestHalfPoint-1; tX2 = (int)tClosestHalfPoint;\r
+                               }\r
+                               else\r
+                               {\r
+                                       tX1 = (int)tClosestHalfPoint; tX2 = (int)tClosestHalfPoint+1;\r
+                               }\r
+\r
+                               // y = mx + c, right? So....\r
+                               tGradient = (double)format.data[ tX1 ] - (double)format.data[ tX2 ];\r
+                               if (tGradient == 0.0f )\r
+                                       tClosestHalfPoint = (double)tX1 + 0.5f;\r
+                               else\r
+                                       tClosestHalfPoint = tX1 - tTargetY / tGradient; \r
+                               tCurveHalf = tClosestHalfPoint;\r
+                               if ( tCurveHalf - tStartOfCycle > 0 )\r
+                                       tHalfWaveLength = tCurveHalf - tStartOfCycle;\r
+                       }\r
+               }\r
+       }\r
+       if ( tStartOfCycle )\r
+       {\r
+               if ( tCurveHalf )\r
+                       tWaveLength = tCurveStart - tCurveHalf;\r
+               else\r
+                       tWaveLength = tCurveStart - tStartOfCycle;\r
+       }\r
+//     if ( tLog )\r
+               ;//printf( "Bottom of curve at %d. OldStart: %f  CurveStart: %f  Wavelength: %f.\n", tPointer, tStartOfCycle, tCurveStart, tWaveLength );\r
+       if ( tWaveLength )\r
+       {\r
+               if ( tStartOfCycle - tLastWave > .00001f /*&& tLastWave > 0.0f*/ )\r
+               {\r
+                       AddWave( wavelengthTable, 1, tStartOfCycle - tLastWave );\r
+               }\r
+               if ( tHalfWaveLength > 0.001f )\r
+               {\r
+                       if ( tEnableCounter  )\r
+                               tCounter++;\r
+                       AddWave( wavelengthTable, 1, tHalfWaveLength );\r
+               }\r
+               if ( tEnableCounter  )\r
+                       tCounter++;\r
+               AddWave( wavelengthTable, 1, tWaveLength );\r
+               tCurveEnd = tCurveStart;\r
+               tLastWave = (double)tPointer;\r
+               tLoggedWave = true;\r
+       }\r
+\r
+       *peak = tPeak; *trough = tTrough; *waveLength = tWaveLength; *pointer = tPointer; *curveStart = tCurveStart; *lastWave = tLastWave;\r
+       *curveEnd = tCurveEnd; *loggedWave = tLoggedWave;\r
+}\r
+\r
+void BuildRawWaveList_Cleaned( struct RAW_Format format, unsigned long offset, double *wavelengthTable, int blocks, bool halfWaves )\r
+{\r
+       unsigned long tPointer = 0;\r
+       signed char  tCurve[ SAMPLE_ENTRIES ];\r
+       double tCurveAverage;\r
+       double tCurveStart = 0, tWaveLength, tCurveEnd = 0;\r
+       enum CurveState { NO_CURVE, CURVE_UP, CURVE_DOWN } tState;\r
+       int i, tBlocks = blocks;\r
+       double tPeak, tTrough;\r
+       unsigned long tWaves = 0;\r
+       bool tLog = false, tLoggedWave = false;\r
+       double tLastWave = 0.0f;\r
+\r
+       for ( i=0 ; i < SAMPLE_ENTRIES ; i++ )\r
+               tCurve[ i ] = 0;\r
+\r
+       tState = NO_CURVE;\r
+\r
+       tPointer = offset;\r
+\r
+       while ( tBlocks != 0 && tPointer < format.size - 1 )\r
+       {\r
+               if ( tPointer >= 1707995 && !tLog )\r
+               {\r
+                       tLog = true;\r
+               }\r
+               AddCurveSample( tCurve, format.data[ tPointer ] );\r
+\r
+               if ( abs( GetCurvePeak( tCurve ) - GetCurveTrough( tCurve )) < gPreferences.minimumSignalLevel ) \r
+               {\r
+                       if ( tLoggedWave == false )\r
+                       {\r
+                               // It's just noise. Forget it.\r
+                               tState = NO_CURVE;\r
+                       }\r
+                       else\r
+                       {\r
+                               if ( tState != NO_CURVE )\r
+                               {\r
+                                       int tLastByte = SAMPLE_ENTRIES-1;\r
+                                       for ( tLastByte = SAMPLE_ENTRIES-1 ; tLastByte > 0 ; tLastByte-- )\r
+                                       {\r
+                                               if ( abs( tCurve[ tLastByte ] ) < 10 )\r
+                                                       break;\r
+                                       }\r
+                                       if ( tPointer < tLastWave )\r
+                                       {\r
+                                               printf(" ERROR in curve.\n" );\r
+                                       }\r
+//                                     AddWave( 1, (double)((double)tPointer - tLastWave) );\r
+                                       if ( tPointer - tLastByte > tCurveEnd )\r
+                                       {\r
+                                               AddWave( wavelengthTable, 1, (double)((double)tPointer - tLastByte - tCurveEnd));\r
+                                               tCurveEnd = (double)(tPointer - tLastByte);\r
+                                               tLastWave = (double)tPointer;\r
+                                       }\r
+                                       tBlocks--;\r
+                                       printf( "Block ends at %ld.\n", tPointer );\r
+                               }\r
+\r
+                               tCurveStart = 0;\r
+                               tPeak = tTrough = tWaves = 0;\r
+                               tWaveLength = 0.0f;\r
+                               tState = NO_CURVE;\r
+                       }\r
+               }\r
+\r
+               switch ( tState )\r
+               {\r
+               case NO_CURVE:\r
+                       if ( HasStartedCurve( tCurve ) )\r
+                       {\r
+                               tState = CURVE_DOWN;\r
+                               if ( tCurveEnd )\r
+                               {\r
+//                                     AddWave( 1, (double)(tPointer - tLastWave) );\r
+                                       //tCurveEnd = 0;\r
+                               }\r
+                               tLoggedWave = false;\r
+                               tCurveStart = (double)(tPointer - 0);   // was 4\r
+                               tCurveAverage = GetCurveAverage( tCurve );\r
+                               printf( "Curve found at %f.\n", tCurveStart );\r
+                               tPeak = tTrough = tWaves = 0;\r
+                               tWaveLength = 0.0f;\r
+                       }\r
+                       break;\r
+               case CURVE_DOWN:\r
+                       if ( format.data[ tPointer ] > format.data[ tPointer - 1 ] && format.data[ tPointer + 1 ] >= format.data[ tPointer ] )\r
+                       {\r
+                               tState = CURVE_UP;\r
+\r
+                               if( tPointer == 13265165 )\r
+                               {\r
+                                       bool test=true;\r
+                               }\r
+                               TriggerWaveAddition( format, wavelengthTable, halfWaves, &tPeak, &tTrough, &tWaveLength, &tPointer, &tCurveStart, &tLastWave, &tCurveEnd, &tLoggedWave );\r
+                               if ( tLog )\r
+                               {\r
+                                       static int tCounter = 0;\r
+//                                     printf( "Wave added at %ld. Counter is %d.\n", tPointer, ++tCounter );\r
+                                       if ( tPointer > 1714369 )\r
+                                       {\r
+                                               bool test=true;\r
+                                       }\r
+                               }\r
+                       }\r
+                       break;\r
+               case CURVE_UP:\r
+                       if ( format.data[ tPointer ] < format.data[ tPointer - 1 ] && format.data[ tPointer + 1 ] <= format.data[ tPointer ] )\r
+                       {\r
+                               tState = CURVE_DOWN;\r
+                               if ( tPeak > 0 )\r
+                               {\r
+                                       tWaveLength = (double)((tPointer-1) - tPeak);\r
+                                       tPeak = tPointer - 0;\r
+                               }\r
+                               else\r
+                               {\r
+                                       tPeak = tPointer - 0;\r
+                                       tWaveLength = (double)((tPeak - tTrough) * 2);\r
+                               }\r
+                               tWaves++;\r
+                       }\r
+                       break;\r
+               default:\r
+                       break;\r
+               }\r
+\r
+               tPointer++;\r
+       }\r
+\r
+       // Last curve.\r
+       TriggerWaveAddition( format, wavelengthTable, halfWaves, &tPeak, &tTrough, &tWaveLength, &tPointer, &tCurveStart, &tLastWave, &tCurveEnd, &tLoggedWave );\r
+}\r
+\r
+void BuildThresholds( struct RAW_Format format, int thresholds, int *thresholdStore, int *wavelengthTable, int *valueTable )\r
+{\r
+       // Find the most common wavelength.\r
+       #define BT_NUMBER_OF_CURVES 20\r
+       #define BT_MINIMUM_WAVES 2\r
+       #define BT_MINIMUM_CURVE_WIDTH 3\r
+\r
+       struct BT_Curve\r
+       {\r
+               int start, end, size, peak;\r
+       } tCurves[ BT_NUMBER_OF_CURVES ];\r
+\r
+       unsigned char tMostCommon[ 3 ]={-1,-1,-1}, tNextPeakUp = 0, tNextPeakDown = 0;\r
+       int i, tValue, tThresholds[ 2 ];\r
+       bool tHasGoneLow = true;\r
+       int tWaveCounter = 0, tSize=0;\r
+\r
+       int tCurveNumber = 0;\r
+\r
+       for ( i = 0 ; i < BT_NUMBER_OF_CURVES ; i++ )\r
+       {\r
+               tCurves[ i ].start = tCurves[ i ].end = -1;\r
+               tCurves[ i ].size = 0; tCurves[ i ].peak = 0;\r
+       }\r
+       for ( i = 2 ; i < NUMBER_OF_THRESHOLDS-2 && tCurveNumber < BT_NUMBER_OF_CURVES ; i++ )\r
+       {\r
+               if ( wavelengthTable[ i ] != -1 )\r
+                       printf( "%d: %d. ", i, wavelengthTable[ i ] );\r
+//             if ( wavelengthTable[ i ] < wavelengthTable[ i+1 ] && wavelengthTable[ i +1] < wavelengthTable[ i+2 ] && tCurves[ tCurveNumber ].start == -1 )\r
+               if ( wavelengthTable[ i ] >= BT_MINIMUM_WAVES && tCurves[ tCurveNumber ].start == -1 )\r
+                       tCurves[ tCurveNumber ].start = i;\r
+\r
+               if ( tCurves[ tCurveNumber ].start != -1 )\r
+               {\r
+                       if ( wavelengthTable[ tCurves[ tCurveNumber ].peak ] < wavelengthTable[ i ] )\r
+                               tCurves[ tCurveNumber ].peak = (tCurves[ tCurveNumber ].start + i) / 2;\r
+                       tCurves[ tCurveNumber ].size += wavelengthTable[ i ];\r
+//                     if ( wavelengthTable[ i + 1 ] < wavelengthTable[ i ] && wavelengthTable[ i + 2 ] < wavelengthTable[ i+1 ] )\r
+                       if ( fabs( i - tCurves[ tCurveNumber ].peak ) > BT_MINIMUM_CURVE_WIDTH && \r
+                               (wavelengthTable[ i ] < BT_MINIMUM_WAVES || (wavelengthTable[ i + 1 ] >= wavelengthTable[ i ] && wavelengthTable[ i + 2 ] >= wavelengthTable[ i + 1 ] && wavelengthTable[ i ] <= wavelengthTable[ i -1 ] && wavelengthTable[ i - 1 ] <= wavelengthTable[ i - 2 ] ))) \r
+                       {\r
+                               tCurves[ tCurveNumber ].end = i;\r
+                               tCurveNumber++;\r
+                       }\r
+               }\r
+       }\r
+\r
+       \r
+       for ( i = 0 ; i < BT_NUMBER_OF_CURVES ; i++ )\r
+       {\r
+               if ( tMostCommon[ 0 ] == 255 || tCurves[ i ].size > tCurves[ tMostCommon[ 0 ] ].size )\r
+               {\r
+                       if ( thresholds == 3 )\r
+                               tMostCommon[ 2 ] = tMostCommon[ 1 ];\r
+                       tMostCommon[ 1 ] = tMostCommon[ 0 ];\r
+                       tMostCommon[ 0 ] = i;\r
+                       printf(" More common than 0. Now %d, %d, %d.\n", tMostCommon[ 0 ], tMostCommon[ 1 ], tMostCommon[ 2 ] );\r
+               }\r
+               else if ( tMostCommon[ 1 ] == 255 || tCurves[ i ].size > tCurves[ tMostCommon[ 1 ] ].size )\r
+               {\r
+                       if ( thresholds == 3 )\r
+                               tMostCommon[ 2 ] = tMostCommon[ 1 ];\r
+                       tMostCommon[ 1 ] = i;\r
+                       printf(" More common than 1. Now %d, %d, %d.\n", tMostCommon[ 0 ], tMostCommon[ 1 ], tMostCommon[ 2 ] );\r
+               }\r
+               else if ( tMostCommon[ 2 ] == 255 || tCurves[ i ].size  > tCurves[ tMostCommon[ 2 ] ].size )\r
+               {\r
+                       if ( thresholds == 3 )\r
+                               tMostCommon[ 2 ] = i;\r
+               }\r
+       }\r
+\r
+       printf( "Most Common are %d, %d, %d.\n", tMostCommon[ 0 ], tMostCommon[ 1 ], tMostCommon[ 2 ] );\r
+\r
+       tValue = 0;\r
+       for ( i = 0 ; i < NUMBER_OF_THRESHOLDS ; i++ )\r
+       {\r
+               if ( i == tMostCommon[ 0 ] || i == tMostCommon[ 1 ] || (thresholds > 2 && i == tMostCommon[ 2 ]) )\r
+               {\r
+                       thresholdStore[ tValue++ ] = tCurves[ i ].start + (tCurves[ i ].end - tCurves[ i ].start) / 2;\r
+               }\r
+       }\r
+\r
+       tThresholds[ 0 ] = gMachineData.converter( (double)(thresholdStore[ 0 ] + ( (double)thresholdStore[ 1 ] - (double)thresholdStore[ 0 ]) * gThresholdDivisor[ 0 ]));\r
+       if ( thresholds > 2 )\r
+               tThresholds[ 1 ] = gMachineData.converter( (double)(thresholdStore[ 1 ] + ( (double)thresholdStore[ 2 ] - (double)thresholdStore[ 1 ]) * gThresholdDivisor[ 1 ]));\r
+       else\r
+               tThresholds[ 1 ] = gMachineData.converter( (double)(thresholdStore[ 1 ] + ( (double)NUMBER_OF_THRESHOLDS-1 - (double)thresholdStore[ 1 ]) * gThresholdDivisor[ 1 ]));\r
+\r
+       printf( "Thresholds: %d (%d), %d (%d).\n", thresholdStore[ 0 ], tThresholds[ 0 ], thresholdStore[ 1 ], tThresholds[ 1 ] );\r
+\r
+       for ( i = 0 ; i < NUMBER_OF_THRESHOLDS ; i ++ )\r
+               valueTable[ i ] = -1;\r
+       for ( i = (int)gMachineData.converter((double)( thresholdStore[ 0 ]) / 2) ; i < tThresholds[ 0 ] ; i++ )        // was 3/4, and 1/4 below.\r
+               valueTable[ i ] = 0;\r
+\r
+       if ( thresholds > 2 )\r
+       {\r
+               for ( i = tThresholds[ 0 ] ; i < tThresholds[ 1 ] ; i++ )\r
+                       valueTable[ i ] = 1;\r
+               for ( i = tThresholds[ 1 ]  ; i < NUMBER_OF_THRESHOLDS - 1 - (tThresholds[ 1 ] / 2) ; i++ )\r
+                       valueTable[ i ] = 2;\r
+       }\r
+       else\r
+       {\r
+               for ( i = tThresholds[ 0 ]  ; i < NUMBER_OF_THRESHOLDS - 1 - (tThresholds[ 0 ] / 2) ; i++ )\r
+                       valueTable[ i ] = 1;\r
+       }\r
+}\r
+\r
+bool BuildWavelengthTable( struct RAW_Format format, double offset, int blocks, int *wavelengthTable )\r
+{\r
+#define BWT_MAX_WAVELENGTH 200\r
+       double tPointer = offset;\r
+       double tWavelength = 0.0f;\r
+       int i, tBlocks = blocks, tWaveCounter = 0;\r
+       double *tWaveCycles, *tNumberOfCycles;\r
+\r
+       tWaveCycles = (double *)malloc( 32 * 1024 * 1024 );\r
+       if ( tWaveCycles == NULL )\r
+       {\r
+               printf(" Out of memory building wavelength table.\n" );\r
+               return false;\r
+       }\r
+       tWaveCycles[ 0 ] = 0.0f;\r
+       tNumberOfCycles = &tWaveCycles[ 0 ];\r
+\r
+       for ( i=0 ; i < NUMBER_OF_THRESHOLDS ; i++ )\r
+               wavelengthTable[ i ] = -1;\r
+\r
+       if ( gAlgorithmType == WAVE )\r
+               BuildRawWaveList_Cleaned( format, (unsigned long)offset, tWaveCycles, blocks, false ); \r
+       else\r
+               BuildRawWaveList( format, (unsigned long)offset, tWaveCycles, blocks, false ); \r
+\r
+       if ( (int)*tNumberOfCycles < 50 )\r
+       {\r
+               // This is no wave!\r
+//             for ( i=0 ; i < NUMBER_OF_THRESHOLDS ; i++ )\r
+//                     wavelengthTable[ i ] = -1;\r
+               printf(" Not enough waves: only %d found.\n", tWaveCounter );\r
+               free( tWaveCycles );\r
+               return false;\r
+       }\r
+\r
+\r
+       for ( i = 0 ; i < (int)*tNumberOfCycles ; i++ )\r
+       {\r
+               if ( tWaveCycles[ i+1 ] < NUMBER_OF_THRESHOLDS )\r
+                       wavelengthTable[ (int)tWaveCycles[ i+1 ] ]++;\r
+       }\r
+\r
+               /*\r
+       while ( tPointer >= 0 && tPointer < format.size )\r
+       {\r
+               tOldPointer = tPointer;\r
+               printf( "Searching for next wave from %f.\n", tPointer );\r
+               tPointer = (double)FindNextWavelengthStart( format, tPointer );\r
+\r
+               if ( tPointer < 0 )\r
+               {\r
+                       printf( "No wavelength found.\n" );     \r
+                       return false;\r
+               }\r
+\r
+               // Now we're pointing to the beginning of a potential wave.\r
+               tWavelength = 128;\r
+               while ( tWavelength > 0 && tWavelength < BWT_MAX_WAVELENGTH )\r
+               {\r
+                       double tOldPointer = tPointer;\r
+                       static bool tLog = false;\r
+\r
+                       if ( tPointer > 6850258 && tLog == false )\r
+                       {\r
+                               tLog = true;\r
+                       }\r
+\r
+                       tWavelength = FindWavelength( format, &tPointer, false, true, true);\r
+\r
+                       if ( tWavelength > 0 && tWavelength < NUMBER_OF_THRESHOLDS )\r
+                       {\r
+                               // We have a valid wavelength!\r
+       if ( (int)tWavelength >= 36 && (int)tWavelength <= 38 )\r
+       {\r
+               bool test=true;\r
+       }\r
+\r
+                               wavelengthTable[ (int)tWavelength ]++;\r
+                       }\r
+                       tWaveCounter++;\r
+               }\r
+               tBlocks--;\r
+               if ( tBlocks == 0 )\r
+               {\r
+                       printf( "End of block found at %f.\n", tPointer );\r
+                       break;\r
+               }\r
+       }\r
+*/\r
+\r
+#if 1 && defined(_DEBUG)\r
+       // Print out the wavelengths.\r
+       {\r
+               int i;\r
+               for ( i=0 ; i<NUMBER_OF_THRESHOLDS ; i++ )\r
+                       if ( wavelengthTable[ i ] > 0 )\r
+                               printf( "%d: %d ", i, wavelengthTable[ i ] );\r
+               printf( "\n" );\r
+       }\r
+#endif\r
+\r
+       printf("Found wave at %f.\n", tPointer );\r
+\r
+\r
+       free( tWaveCycles );\r
+       return true;\r
+}\r
+\r
+double FindWavelength( struct RAW_Format format, double *pointer, bool firstHalfWave, bool preParse, bool halfWaves, double *wavelengthTable )\r
+{\r
+       // Find out how long before we're going under again.\r
+       double tPointer = *pointer;\r
+       bool tHasBeenValid = false;\r
+       double tWavelength = 0, tUpWaveLength = 0;\r
+       bool tWarn = false;\r
+       int tAmplitude = 0;\r
+       double tStartSearch = *pointer;\r
+       bool tCurveIsNegative = false;\r
+\r
+       while( tPointer < format.size && tHasBeenValid == false )\r
+       {\r
+               if ( halfWaves )\r
+               {\r
+                       bool tCorrectWave = false;\r
+                       // Half-waves mean use amplitude on the -ve part too, so we use 0 as a reference point.\r
+                       tAmplitude = 0;\r
+                       while ( tCorrectWave == false && tPointer < format.size )\r
+                       {\r
+                               while ( tPointer < format.size && format.data[ (int)tPointer ] == 0 )\r
+                                       tPointer++;\r
+                               if ( (/*firstHalfWave && */format.data[ (int)tPointer ] < 0) || (/*!firstHalfWave &&*/ format.data[ (int)tPointer ] > 0) )\r
+                                       tCorrectWave = true;\r
+                               else\r
+                                       tPointer++;\r
+                       }\r
+                       tCurveIsNegative = (format.data[ (int)tPointer ] < 0) /*firstHalfWave*/;\r
+               }\r
+               else\r
+               {\r
+                       if ( format.data[ (int)tPointer ] < tAmplitude )\r
+                               tAmplitude = format.data[ (int)tPointer ];\r
+               }\r
+               tPointer++;\r
+\r
+               if ( tPointer >= format.size )\r
+               {\r
+                       *pointer = tPointer;\r
+                       return 0;\r
+               }\r
+\r
+               while ( tPointer < format.size && format.data[ (int)tPointer ] == 0 )\r
+                       tPointer++;\r
+\r
+               if ( tCurveIsNegative )\r
+               {\r
+                       while ( tPointer < format.size && format.data[ (int)tPointer ] < 0 )\r
+                       {\r
+                               if ( (abs(format.data[ (int)tPointer ]) - tAmplitude ) >= gPreferences.minimumSignalLevel / 2 )\r
+                                       tHasBeenValid = true;\r
+                               tPointer++;\r
+                       }\r
+               }\r
+               else\r
+               {\r
+                       while ( tPointer < format.size && format.data[ (int)tPointer ] > 0 )\r
+                       {\r
+                               if ( (format.data[ (int)tPointer ] - tAmplitude ) >= gPreferences.minimumSignalLevel / (halfWaves ? 2 : 1) )\r
+                                       tHasBeenValid = true;\r
+                               tPointer++;\r
+                       }\r
+               }\r
+\r
+               if ( tPointer == format.size )\r
+               {\r
+                       *pointer = tPointer;\r
+                       return 0;\r
+               }\r
+       }\r
+\r
+       tWavelength = (tPointer - *pointer);\r
+\r
+       // It's valid! Yay!\r
+       *pointer = tPointer;\r
+\r
+       if ( preParse == false )\r
+       {\r
+               if ( tPointer - tWavelength != tStartSearch )\r
+                       AddWave( wavelengthTable, 1, (double)(tPointer - tWavelength - tStartSearch) );\r
+               AddWave( wavelengthTable, 1, tWavelength );\r
+       }\r
+\r
+       return tWavelength;\r
+}\r
+\r
+unsigned long ConvertToCycles( double samples )\r
+{\r
+       double tLengthInSeconds;\r
+       unsigned long tCycles;\r
+       unsigned long tSpeed;\r
+\r
+       tLengthInSeconds = samples / gWAVFormat.sampleRate;\r
+       if ( gVideoType == PAL )\r
+               tSpeed = gMachineData.speed_PAL;\r
+       else\r
+               tSpeed = gMachineData.speed_NTSC;\r
+       tCycles = (unsigned long)(((double)tSpeed) * tLengthInSeconds);\r
+       \r
+       return tCycles;\r
+}\r
+\r
+double ConvertFromCycles( int cycles )\r
+{\r
+       double tLengthInSeconds;\r
+       double tSamples;\r
+       unsigned long tSpeed;\r
+\r
+       if ( gVideoType == PAL )\r
+               tSpeed = gMachineData.speed_PAL;\r
+       else\r
+               tSpeed = gMachineData.speed_NTSC;\r
+       tLengthInSeconds = (double)cycles / (double)tSpeed;\r
+       tSamples = (double)(tLengthInSeconds * (double)gOutputWAVFormat.sampleRate );\r
+       \r
+       return tSamples;\r
+}\r
+\r
+double ConvertFromCyclesToSeconds( int cycles )\r
+{\r
+       double tLengthInSeconds;\r
+       unsigned long tSpeed;\r
+\r
+       if ( gVideoType == PAL )\r
+               tSpeed = gMachineData.speed_PAL;\r
+       else\r
+               tSpeed = gMachineData.speed_NTSC;\r
+       tLengthInSeconds = (double)cycles / (double)tSpeed;\r
+       \r
+       return tLengthInSeconds;\r
+}\r
diff --git a/src/Sample.c.bak.c b/src/Sample.c.bak.c
new file mode 100644 (file)
index 0000000..4adbfdc
--- /dev/null
@@ -0,0 +1,696 @@
+// Tool functions for getting the data ready to parse (if necessary).\r
+\r
+#include <stdio.h>\r
+#include <math.h>\r
+\r
+#include "UberCassette.h"\r
+#include "Sample.h"\r
+#include "WAV.h"\r
+\r
+\r
+const unsigned char gTriggerValue = 0x06;\r
+#define SAMPLE_ENTRIES 20\r
+\r
+void BuildRawWaveList( struct RAW_Format format )\r
+{\r
+       double tPointer = 0, tWaveStart;\r
+       bool tFirstWave = true;\r
+\r
+       tWaveStart = tPointer;\r
+       tPointer = FindNextWavelengthStart( format, tPointer );\r
+       AddRawCycle( (double) tPointer - tWaveStart );\r
+\r
+    printf( "Building RAW Wave list.\n" );\r
+\r
+       while ( tPointer < format.size )\r
+       {\r
+               FindWavelength( format, &tPointer, tFirstWave, false, false );\r
+               tFirstWave = !tFirstWave;\r
+       }\r
+       printf( "RAW Wave list done.\n" );\r
+}\r
+\r
+double FindNextWavelengthStart( struct RAW_Format format, double pointer )\r
+{\r
+       // Find the beginning of a waveform.\r
+       unsigned long tPointer = (unsigned long)pointer;\r
+\r
+       while ( format.data[ tPointer ] < gTriggerValue && tPointer < format.size )\r
+               tPointer++;\r
+\r
+       if ( tPointer == format.size )\r
+               return -1;      // No more waveforms here.\r
+\r
+       while ( format.data[ tPointer ] > 0 && tPointer < format.size )\r
+               tPointer++;\r
+\r
+       if ( tPointer == format.size )\r
+               return -1;      // Still no more waveforms.\r
+\r
+       return (double)tPointer;\r
+}\r
+\r
+\r
+void AddCurveSample( signed char *curve, unsigned char sample )\r
+{\r
+       int i;\r
+\r
+       for ( i = 0 ; i < SAMPLE_ENTRIES-1 ; i++ )\r
+               curve[ i ] = curve[ i + 1 ];\r
+       curve[ i ] = sample;\r
+}\r
+\r
+signed char GetCurveAverage( signed char *curve )\r
+{\r
+       signed char tAverage;\r
+       tAverage = ((int)curve[ SAMPLE_ENTRIES-5 ] + (int)curve[ SAMPLE_ENTRIES-4 ] + (int)curve[ SAMPLE_ENTRIES-3 ] + (int)curve[ SAMPLE_ENTRIES-2 ] + (int)curve[ SAMPLE_ENTRIES-1 ]) / 5;\r
+       return tAverage;\r
+}\r
+\r
+signed char GetCurvePeak( signed char *curve )\r
+{\r
+       signed char tPeak=0;\r
+       int i;\r
+\r
+       for ( i=0 ; i<SAMPLE_ENTRIES ; i++ )\r
+       {\r
+               if ( tPeak < curve[ i ] )\r
+                       tPeak = curve[ i ];\r
+       }\r
+       return tPeak;\r
+}\r
+\r
+signed char GetCurveTrough( signed char *curve )\r
+{\r
+       signed char tTrough=0;\r
+       int i;\r
+\r
+       for ( i=0 ; i<SAMPLE_ENTRIES ; i++ )\r
+       {\r
+               if ( tTrough > curve[ i ] )\r
+                       tTrough = curve[ i ];\r
+       }\r
+       return tTrough;\r
+}\r
+\r
+int HasStartedCurve( signed char *curve )\r
+{\r
+       signed char tTrough = GetCurveTrough( curve );\r
+\r
+       if ( tTrough > -gTriggerValue )\r
+               return false;\r
+\r
+       if ( curve[ SAMPLE_ENTRIES-1 ] > curve[ SAMPLE_ENTRIES-2 ] )\r
+               return false;   // We're going up-hill.\r
+\r
+       return true;\r
+}\r
+\r
+void AddWave( int amount, double cycles )\r
+{\r
+       int tCounter = 0;\r
+\r
+       const unsigned long tCycleLengths[35] = { -1,-1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2 };\r
+\r
+       for ( tCounter = 0 ; tCounter < amount ; tCounter++ )\r
+       {\r
+               if ( cycles < 0.0f )\r
+               {\r
+                       printf( "ERROR in amount of cycles.\n" );\r
+               }\r
+               if ( cycles > 1000 )\r
+               {\r
+                       bool test=true;\r
+               }\r
+               AddRawCycle( cycles );\r
+       }\r
+}\r
+\r
+void TriggerWaveAddition( struct RAW_Format format, double *peak, double *trough, double *waveLength, unsigned long *pointer, double *curveStart, double *lastWave, double *curveEnd, bool *loggedWave )\r
+{\r
+       double tOldTrough = 0.0f, tPeak = *peak, tTrough = *trough, tCurveStart = *curveStart, tLastWave = *lastWave, tCurveEnd = *curveEnd;\r
+       bool tLoggedWave = *loggedWave;\r
+       double tWaveLength = *waveLength;\r
+       unsigned long tPointer = *pointer;\r
+       double tCurveHalf = 0.0f;\r
+       double tTargetAmplitude, tHalfWaveLength = 0.0f;\r
+       double tClosestPoint, tClosestHalfPoint;                \r
+       double tStartOfCycle = tCurveStart;\r
+       int tTroughAmplitude=0, tPeakAmplitude=0, tOldTroughAmplitude=0;\r
+\r
+       tOldTrough = tTrough;\r
+       tTrough = tPointer - 1;\r
+\r
+       if ( tTrough && tPeak )\r
+       {\r
+               tTroughAmplitude = format.data[ (int)tTrough ]; tPeakAmplitude = format.data[ (int)tPeak ];                                     \r
+               if ( tOldTrough )\r
+                       tOldTroughAmplitude = format.data[ (int)tOldTrough ];\r
+       }\r
+\r
+       // Use this if we don't have a full wave's data.\r
+       if ( tOldTrough )\r
+               tWaveLength = (double)(tPointer - tOldTrough);\r
+\r
+       if ( tPeak && tTrough )\r
+       {\r
+               if ( gAlgorithmType == SAW )\r
+               {\r
+                       if ( gMachineData.halfWave )\r
+                       {\r
+                               tCurveHalf = tOldTrough + (tPeak - tOldTrough) / 2.0f;\r
+                               tHalfWaveLength = tCurveHalf - tStartOfCycle;\r
+                               tCurveStart = tPeak + (tTrough - tPeak) / 2.0f;\r
+                       }\r
+               }\r
+               else\r
+               {\r
+                       int i;\r
+                       int tX1, tX2;\r
+                       double tGradient, tTargetY;\r
+                       tTargetAmplitude = (tPeakAmplitude + tTroughAmplitude) / 2.0f;\r
+                       tClosestPoint = tTrough;\r
+                       for ( i = (int)tPeak ; i < (int)tTrough ; i++ )\r
+                       {\r
+                               if ( fabs( (double)format.data[ i ] - tTargetAmplitude ) < fabs((double)format.data[ (int)tClosestPoint ] - tTargetAmplitude))\r
+                                       tClosestPoint = (double) i;\r
+                       }\r
+                       if ( tOldTrough && gMachineData.halfWave )\r
+                       {\r
+                               tClosestHalfPoint = (double)tPeak;\r
+                               for ( i = (int)tPeak ; i > (int)tOldTrough ; i-- )\r
+                               {\r
+                                       if ( fabs( (double)format.data[ i ] - tTargetAmplitude ) < (double)format.data[ (int)tClosestHalfPoint ]- tTargetAmplitude )\r
+                                               tClosestHalfPoint = (double) i;\r
+                               }\r
+                       }\r
+                       \r
+                       // Extrapolate the actual curve trigger.\r
+                       if ( format.data[ (int)tClosestPoint ] > tTargetAmplitude )\r
+                       {\r
+                               tX1 = (int)tClosestPoint; tX2 = (int)tClosestPoint+1;\r
+                       }\r
+                       else\r
+                       {\r
+                               tX1 = (int)tClosestPoint-1; tX2 = (int)tClosestPoint;\r
+                       }\r
+\r
+                       // y = mx + c, right? So....\r
+                       tTargetY = tTargetAmplitude - (double)format.data[ (int)tX1 ];\r
+                       tGradient = (double)format.data[ tX1 ] - (double)format.data[ tX2 ];\r
+                       if (tGradient == 0.0f )\r
+                               tClosestPoint = (double)tX1 + 0.5f;\r
+                       else\r
+                               tClosestPoint = tX1 - tTargetY / tGradient;     \r
+                       tCurveStart = tClosestPoint;    // Set the end of the curve, beginning of the next.\r
+                       if ( tCurveStart > tPointer )\r
+                       {\r
+                               printf( "** WARNING ** Invalid curve length.\n" );\r
+                       }\r
+\r
+                       if ( gMachineData.halfWave )\r
+                       {\r
+                               // Extrapolate the actual curve trigger.\r
+                               if ( format.data[ (int)tClosestHalfPoint ] > tTargetAmplitude )\r
+                               {\r
+                                       tX1 = (int)tClosestHalfPoint-1; tX2 = (int)tClosestHalfPoint;\r
+                               }\r
+                               else\r
+                               {\r
+                                       tX1 = (int)tClosestHalfPoint; tX2 = (int)tClosestHalfPoint+1;\r
+                               }\r
+\r
+                               // y = mx + c, right? So....\r
+                               tGradient = (double)format.data[ tX1 ] - (double)format.data[ tX2 ];\r
+                               if (tGradient == 0.0f )\r
+                                       tClosestHalfPoint = (double)tX1 + 0.5f;\r
+                               else\r
+                                       tClosestHalfPoint = tX1 - tTargetY / tGradient; \r
+                               tCurveHalf = tClosestHalfPoint;\r
+                               if ( tCurveHalf - tStartOfCycle > 0 )\r
+                                       tHalfWaveLength = tCurveHalf - tStartOfCycle;\r
+                       }\r
+               }\r
+       }\r
+       if ( tStartOfCycle )\r
+       {\r
+               if ( tCurveHalf )\r
+                       tWaveLength = tCurveStart - tCurveHalf;\r
+               else\r
+                       tWaveLength = tCurveStart - tStartOfCycle;\r
+       }\r
+//     if ( tLog )\r
+               ;//printf( "Bottom of curve at %d. OldStart: %f  CurveStart: %f  Wavelength: %f.\n", tPointer, tStartOfCycle, tCurveStart, tWaveLength );\r
+       if ( tWaveLength )\r
+       {\r
+               if ( tStartOfCycle - tLastWave > .00001f /*&& tLastWave > 0.0f*/ )\r
+                       AddWave( 1, tStartOfCycle - tLastWave );\r
+               if ( tHalfWaveLength > 0.001f )\r
+                       AddWave( 1, tHalfWaveLength );\r
+               AddWave( 1, tWaveLength );\r
+               tCurveEnd = tCurveStart;\r
+               tLastWave = (double)tPointer;\r
+               tLoggedWave = true;\r
+       }\r
+\r
+       *peak = tPeak; *trough = tTrough; *waveLength = tWaveLength; *pointer = tPointer; *curveStart = tCurveStart; *lastWave = tLastWave;\r
+       *curveEnd = tCurveEnd; *loggedWave = tLoggedWave;\r
+}\r
+\r
+void BuildRawWaveList_Cleaned( struct RAW_Format format )\r
+{\r
+       unsigned long tPointer = 0;\r
+       signed char  tCurve[ SAMPLE_ENTRIES ];\r
+       double tCurveAverage;\r
+       double tCurveStart = 0, tWaveLength, tCurveEnd = 0;\r
+       enum CurveState { NO_CURVE, CURVE_UP, CURVE_DOWN } tState;\r
+       int i;\r
+       double tPeak, tTrough;\r
+       unsigned long tWaves = 0;\r
+       bool tLog = false, tLoggedWave = false;\r
+       double tLastWave = 0.0f;\r
+\r
+       for ( i=0 ; i < SAMPLE_ENTRIES ; i++ )\r
+               tCurve[ i ] = 0;\r
+\r
+       tState = NO_CURVE;\r
+\r
+       tPointer = 0;\r
+\r
+       while ( tPointer < format.size - 1 )\r
+       {\r
+               if ( tPointer == 29826018 )\r
+               {\r
+                       tLog = true;\r
+               }\r
+               AddCurveSample( tCurve, format.data[ tPointer ] );\r
+\r
+               if ( abs( GetCurvePeak( tCurve ) - GetCurveTrough( tCurve )) < gTriggerValue ) \r
+               {\r
+                       if ( tLoggedWave == false )\r
+                       {\r
+                               // It's just noise. Forget it.\r
+                               tState = NO_CURVE;\r
+                       }\r
+                       else\r
+                       {\r
+                               if ( tState != NO_CURVE )\r
+                               {\r
+                                       int tLastByte = SAMPLE_ENTRIES-1;\r
+                                       for ( tLastByte = SAMPLE_ENTRIES-1 ; tLastByte > 0 ; tLastByte-- )\r
+                                       {\r
+                                               if ( abs( tCurve[ tLastByte ] ) < 10 )\r
+                                                       break;\r
+                                       }\r
+                                       if ( tPointer < tLastWave )\r
+                                       {\r
+                                               printf(" ERROR in curve.\n" );\r
+                                       }\r
+//                                     AddWave( 1, (double)((double)tPointer - tLastWave) );\r
+                                       if ( tPointer - tLastByte > tCurveEnd )\r
+                                       {\r
+                                               AddWave( 1, (double)((double)tPointer - tLastByte - tCurveEnd));\r
+                                               tCurveEnd = (double)(tPointer - tLastByte);\r
+                                               tLastWave = (double)tPointer;\r
+                                       }\r
+                               }\r
+\r
+                               tCurveStart = 0;\r
+                               tPeak = tTrough = tWaves = 0;\r
+                               tWaveLength = 0.0f;\r
+                               tState = NO_CURVE;\r
+                       }\r
+               }\r
+\r
+               switch ( tState )\r
+               {\r
+               case NO_CURVE:\r
+                       if ( HasStartedCurve( tCurve ) )\r
+                       {\r
+                               tState = CURVE_DOWN;\r
+                               if ( tCurveEnd )\r
+                               {\r
+//                                     AddWave( 1, (double)(tPointer - tLastWave) );\r
+                                       //tCurveEnd = 0;\r
+                               }\r
+                               tLoggedWave = false;\r
+                               tCurveStart = (double)(tPointer - 0);   // was 4\r
+                               tCurveAverage = GetCurveAverage( tCurve );\r
+                               printf( "Curve found at %f.\n", tCurveStart );\r
+                               tPeak = tTrough = tWaves = 0;\r
+                               tWaveLength = 0.0f;\r
+                       }\r
+                       break;\r
+               case CURVE_DOWN:\r
+                       if ( format.data[ tPointer ] > format.data[ tPointer - 1 ] && format.data[ tPointer + 1 ] >= format.data[ tPointer ] )\r
+                       {\r
+                               tState = CURVE_UP;\r
+\r
+                               TriggerWaveAddition( format, &tPeak, &tTrough, &tWaveLength, &tPointer, &tCurveStart, &tLastWave, &tCurveEnd, &tLoggedWave );\r
+                       }\r
+                       break;\r
+               case CURVE_UP:\r
+                       if ( format.data[ tPointer ] < format.data[ tPointer - 1 ] && format.data[ tPointer + 1 ] <= format.data[ tPointer ] )\r
+                       {\r
+                               tState = CURVE_DOWN;\r
+                               if ( tPeak > 0 )\r
+                               {\r
+                                       tWaveLength = (double)((tPointer-1) - tPeak);\r
+                                       tPeak = tPointer - 0;\r
+                               }\r
+                               else\r
+                               {\r
+                                       tPeak = tPointer - 0;\r
+                                       tWaveLength = (double)((tPeak - tTrough) * 2);\r
+                               }\r
+                               tWaves++;\r
+                       }\r
+                       break;\r
+               default:\r
+                       break;\r
+               }\r
+\r
+               tPointer++;\r
+       }\r
+\r
+       // Last curve.\r
+       TriggerWaveAddition( format, &tPeak, &tTrough, &tWaveLength, &tPointer, &tCurveStart, &tLastWave, &tCurveEnd, &tLoggedWave );\r
+}\r
+\r
+void BuildThresholds( struct RAW_Format format, int thresholds, int *thresholdStore, int *wavelengthTable, int *valueTable )\r
+{\r
+       // Find the most common wavelength.\r
+       #define BT_NUMBER_OF_CURVES 20\r
+       #define BT_MINIMUM_WAVES 6\r
+\r
+       struct BT_Curve\r
+       {\r
+               int start, end, size;\r
+       } tCurves[ BT_NUMBER_OF_CURVES ];\r
+\r
+       unsigned char tMostCommon[ 3 ]={-1,-1,-1}, tNextPeakUp = 0, tNextPeakDown = 0;\r
+       int i, tValue, tThresholds[ 2 ];\r
+       bool tHasGoneLow = true;\r
+       int tWaveCounter = 0, tSize=0;\r
+\r
+       int tCurveNumber = 0;\r
+\r
+       for ( i = 0 ; i < BT_NUMBER_OF_CURVES ; i++ )\r
+       {\r
+               tCurves[ i ].start = tCurves[ i ].end = -1;\r
+               tCurves[ i ].size = 0;\r
+       }\r
+       for ( i = 2 ; i < NUMBER_OF_THRESHOLDS-2 && tCurveNumber < BT_NUMBER_OF_CURVES ; i++ )\r
+       {\r
+               if ( wavelengthTable[ i ] != -1 )\r
+                       printf( "%d: %d. ", i, wavelengthTable[ i ] );\r
+//             if ( wavelengthTable[ i ] < wavelengthTable[ i+1 ] && wavelengthTable[ i +1] < wavelengthTable[ i+2 ] && tCurves[ tCurveNumber ].start == -1 )\r
+               if ( wavelengthTable[ i ] >= BT_MINIMUM_WAVES && tCurves[ tCurveNumber ].start == -1 )\r
+                       tCurves[ tCurveNumber ].start = i;\r
+\r
+               if ( tCurves[ tCurveNumber ].start != -1 )\r
+               {\r
+                       tCurves[ tCurveNumber ].size += wavelengthTable[ i ];\r
+//                     if ( wavelengthTable[ i + 1 ] < wavelengthTable[ i ] && wavelengthTable[ i + 2 ] < wavelengthTable[ i+1 ] )\r
+                       if ( wavelengthTable[ i ] < BT_MINIMUM_WAVES || (wavelengthTable[ i + 1 ] > wavelengthTable[ i ] && wavelengthTable[ i ] < wavelengthTable[ i -1 ] && wavelengthTable[ i - 1 ] < wavelengthTable[ i - 2 ] )) \r
+                       {\r
+                               tCurves[ tCurveNumber ].end = i;\r
+                               tCurveNumber++;\r
+                       }\r
+               }\r
+       }\r
+\r
+       \r
+       for ( i = 0 ; i < BT_NUMBER_OF_CURVES ; i++ )\r
+       {\r
+               if ( tMostCommon[ 0 ] == 255 || tCurves[ i ].size > tCurves[ tMostCommon[ 0 ] ].size )\r
+               {\r
+                       if ( thresholds == 3 )\r
+                               tMostCommon[ 2 ] = tMostCommon[ 1 ];\r
+                       tMostCommon[ 1 ] = tMostCommon[ 0 ];\r
+                       tMostCommon[ 0 ] = i;\r
+                       printf(" More common than 0. Now %d, %d, %d.\n", tMostCommon[ 0 ], tMostCommon[ 1 ], tMostCommon[ 2 ] );\r
+               }\r
+               else if ( tMostCommon[ 1 ] == 255 || tCurves[ i ].size > tCurves[ tMostCommon[ 1 ] ].size )\r
+               {\r
+                       if ( thresholds == 3 )\r
+                               tMostCommon[ 2 ] = tMostCommon[ 1 ];\r
+                       tMostCommon[ 1 ] = i;\r
+                       printf(" More common than 1. Now %d, %d, %d.\n", tMostCommon[ 0 ], tMostCommon[ 1 ], tMostCommon[ 2 ] );\r
+               }\r
+               else if ( tCurves[ i ].size  > tCurves[ tMostCommon[ 2 ] ].size )\r
+               {\r
+                       if ( thresholds == 3 )\r
+                               tMostCommon[ 2 ] = i;\r
+               }\r
+       }\r
+\r
+       printf( "Most Common are %d, %d, %d.\n", tMostCommon[ 0 ], tMostCommon[ 1 ], tMostCommon[ 2 ] );\r
+/*     tValue = 0;\r
+       for ( i = 0 ; i < BT_NUMBER_OF_CURVES ; i++ )\r
+       {\r
+               if ( i == tMostCommon[ 0 ] || i == tMostCommon[ 1 ] || i == tMostCommon[ 2 ] )\r
+                       thresholdStore[ tValue++ ] = i;\r
+       }\r
+*/\r
+//     for ( i=0 ; i<3 ; i++ )\r
+//             thresholdStore[ i ] = NUMBER_OF_THRESHOLDS - 1;\r
+\r
+       tValue = 0;\r
+       for ( i = 0 ; i < NUMBER_OF_THRESHOLDS ; i++ )\r
+       {\r
+               if ( i == tMostCommon[ 0 ] || i == tMostCommon[ 1 ] || i == tMostCommon[ 2 ] )\r
+               {\r
+                       thresholdStore[ tValue++ ] = tCurves[ i ].start + (tCurves[ i ].end - tCurves[ i ].start) / 2;\r
+               }\r
+       }\r
+\r
+       tThresholds[ 0 ] = gMachineData.converter( (double)(thresholdStore[ 0 ] + ( (double)thresholdStore[ 1 ] - (double)thresholdStore[ 0 ]) * gThresholdDivisor[ 0 ]));\r
+       tThresholds[ 1 ] = gMachineData.converter( (double)(thresholdStore[ 1 ] + ( (double)thresholdStore[ 2 ] - (double)thresholdStore[ 1 ]) * gThresholdDivisor[ 1 ]));\r
+\r
+       printf( "Thresholds: %d (%d), %d (%d).\n", thresholdStore[ 0 ], tThresholds[ 0 ], thresholdStore[ 1 ], tThresholds[ 1 ] );\r
+\r
+       for ( i = 0 ; i < NUMBER_OF_THRESHOLDS ; i ++ )\r
+               valueTable[ i ] = -1;\r
+       for ( i = (int)gMachineData.converter((double)( thresholdStore[ 0 ]) / 2) ; i < tThresholds[ 0 ] ; i++ )        // was 3/4, and 1/4 below.\r
+               valueTable[ i ] = 0;\r
+       for ( i = tThresholds[ 0 ] ; i < tThresholds[ 1 ] ; i++ )\r
+               valueTable[ i ] = 1;\r
+\r
+       if ( thresholds > 2 )\r
+       {\r
+               for ( i = tThresholds[ 1 ]  ; i < NUMBER_OF_THRESHOLDS - 1 - (tThresholds[ 1 ] / 2) ; i++ )\r
+                       valueTable[ i ] = 2;\r
+       }\r
+       else\r
+               valueTable[ 2 ] = -1;\r
+}\r
+\r
+bool BuildWavelengthTable( struct RAW_Format format, double offset, int blocks, int *wavelengthTable )\r
+{\r
+#define BWT_MAX_WAVELENGTH 200\r
+       double tPointer = offset;\r
+       double tWavelength = 0.0f;\r
+       double tOldPointer;\r
+       int i, tBlocks = blocks, tWaveCounter = 0;\r
+\r
+       for ( i=0 ; i < NUMBER_OF_THRESHOLDS ; i++ )\r
+               wavelengthTable[ i ] = -1;\r
+\r
+       while ( tPointer >= 0 && tPointer < format.size )\r
+       {\r
+               tOldPointer = tPointer;\r
+               printf( "Searching for next wave from %f.\n", tPointer );\r
+               tPointer = (double)FindNextWavelengthStart( format, tPointer );\r
+\r
+               if ( tPointer < 0 )\r
+               {\r
+                       printf( "No wavelength found.\n" );     \r
+                       return false;\r
+               }\r
+\r
+               // Now we're pointing to the beginning of a potential wave.\r
+               tWavelength = 128;\r
+               while ( tWavelength > 0 && tWavelength < BWT_MAX_WAVELENGTH )\r
+               {\r
+                       double tOldPointer = tPointer;\r
+                       static bool tLog = false;\r
+\r
+                       if ( tPointer > 6850258 && tLog == false )\r
+                       {\r
+                               tLog = true;\r
+                       }\r
+\r
+                       tWavelength = FindWavelength( format, &tPointer, false, true, true);\r
+\r
+                       if ( tWavelength > 0 && tWavelength < NUMBER_OF_THRESHOLDS )\r
+                       {\r
+                               // We have a valid wavelength!\r
+                               wavelengthTable[ (int)tWavelength ]++;\r
+                       }\r
+                       tWaveCounter++;\r
+               }\r
+               tBlocks--;\r
+               if ( tBlocks == 0 )\r
+               {\r
+                       printf( "End of block found at %f.\n", tPointer );\r
+                       break;\r
+               }\r
+       }\r
+\r
+       if ( tWaveCounter < 50 )\r
+       {\r
+               // This is no wave!\r
+//             for ( i=0 ; i < NUMBER_OF_THRESHOLDS ; i++ )\r
+//                     wavelengthTable[ i ] = -1;\r
+               printf(" Not enough waves: only %d found.\n", tWaveCounter );\r
+               return false;\r
+       }\r
+\r
+#if 1 && defined(_DEBUG)\r
+       // Print out the wavelengths.\r
+       {\r
+               int i;\r
+               for ( i=0 ; i<NUMBER_OF_THRESHOLDS ; i++ )\r
+                       if ( wavelengthTable[ i ] > 0 )\r
+                               printf( "%d: %d ", i, wavelengthTable[ i ] );\r
+               printf( "\n" );\r
+       }\r
+#endif\r
+\r
+       printf("Found wave at %f.\n", tPointer );\r
+\r
+       return true;\r
+}\r
+\r
+double FindWavelength( struct RAW_Format format, double *pointer, bool firstHalfWave, bool preParse, bool fullWave )\r
+{\r
+       // Find out how long before we're going under again.\r
+       double tPointer = *pointer;\r
+       bool tHasBeenValid = false;\r
+       double tWavelength = 0, tUpWaveLength = 0;\r
+       bool tWarn = false;\r
+       int tAmplitude = 0;\r
+       double tStartSearch = *pointer;\r
+       bool tCurveIsNegative = false;\r
+\r
+       while( tPointer < format.size && tHasBeenValid == false )\r
+       {\r
+               if ( gMachineData.halfWave && !fullWave )\r
+               {\r
+                       bool tCorrectWave = false;\r
+                       // Half-waves mean use amplitude on the -ve part too, so we use 0 as a reference point.\r
+                       tAmplitude = 0;\r
+                       while ( tCorrectWave == false && tPointer < format.size )\r
+                       {\r
+                               while ( tPointer < format.size && format.data[ (int)tPointer ] == 0 )\r
+                                       tPointer++;\r
+                               if ( (/*firstHalfWave && */format.data[ (int)tPointer ] < 0) || (/*!firstHalfWave &&*/ format.data[ (int)tPointer ] > 0) )\r
+                                       tCorrectWave = true;\r
+                               else\r
+                                       tPointer++;\r
+                       }\r
+                       tCurveIsNegative = (format.data[ (int)tPointer ] < 0) /*firstHalfWave*/;\r
+               }\r
+               else\r
+               {\r
+                       if ( format.data[ (int)tPointer ] < tAmplitude )\r
+                               tAmplitude = format.data[ (int)tPointer ];\r
+               }\r
+               tPointer++;\r
+\r
+               if ( tPointer >= format.size )\r
+               {\r
+                       *pointer = tPointer;\r
+                       return 0;\r
+               }\r
+\r
+               while ( tPointer < format.size && format.data[ (int)tPointer ] == 0 )\r
+                       tPointer++;\r
+\r
+               if ( tCurveIsNegative )\r
+               {\r
+                       while ( tPointer < format.size && format.data[ (int)tPointer ] < 0 )\r
+                       {\r
+                               if ( (abs(format.data[ (int)tPointer ]) - tAmplitude ) >= gTriggerValue / 2 )\r
+                                       tHasBeenValid = true;\r
+                               tPointer++;\r
+                       }\r
+               }\r
+               else\r
+               {\r
+                       while ( tPointer < format.size && format.data[ (int)tPointer ] > 0 )\r
+                       {\r
+                               if ( (format.data[ (int)tPointer ] - tAmplitude ) >= gTriggerValue / (gMachineData.halfWave ? 2 : 1) )\r
+                                       tHasBeenValid = true;\r
+                               tPointer++;\r
+                       }\r
+               }\r
+\r
+               if ( tPointer == format.size )\r
+               {\r
+                       *pointer = tPointer;\r
+                       return 0;\r
+               }\r
+       }\r
+\r
+       tWavelength = (tPointer - *pointer);\r
+\r
+       // It's valid! Yay!\r
+       *pointer = tPointer;\r
+\r
+       if ( preParse == false )\r
+       {\r
+               if ( tPointer - tWavelength != tStartSearch )\r
+                       AddWave( 1, (double)(tPointer - tWavelength - tStartSearch) );\r
+               AddWave( 1, tWavelength );\r
+       }\r
+\r
+       return tWavelength;\r
+}\r
+\r
+unsigned long ConvertToCycles( double samples )\r
+{\r
+       double tLengthInSeconds;\r
+       unsigned long tCycles;\r
+       unsigned long tSpeed;\r
+\r
+       tLengthInSeconds = samples / gWAVFormat.sampleRate;\r
+       if ( gVideoType == PAL )\r
+               tSpeed = gMachineData.speed_PAL;\r
+       else\r
+               tSpeed = gMachineData.speed_NTSC;\r
+       tCycles = (unsigned long)(((double)tSpeed) * tLengthInSeconds);\r
+       \r
+       return tCycles;\r
+}\r
+\r
+double ConvertFromCycles( int cycles )\r
+{\r
+       double tLengthInSeconds;\r
+       double tSamples;\r
+       unsigned long tSpeed;\r
+\r
+       if ( gVideoType == PAL )\r
+               tSpeed = gMachineData.speed_PAL;\r
+       else\r
+               tSpeed = gMachineData.speed_NTSC;\r
+       tLengthInSeconds = (double)cycles / (double)tSpeed;\r
+       tSamples = (double)(tLengthInSeconds * (double)gOutputWAVFormat.sampleRate );\r
+       \r
+       return tSamples;\r
+}\r
+\r
+double ConvertFromCyclesToSeconds( int cycles )\r
+{\r
+       double tLengthInSeconds;\r
+       unsigned long tSpeed;\r
+\r
+       if ( gVideoType == PAL )\r
+               tSpeed = gMachineData.speed_PAL;\r
+       else\r
+               tSpeed = gMachineData.speed_NTSC;\r
+       tLengthInSeconds = (double)cycles / (double)tSpeed;\r
+       \r
+       return tLengthInSeconds;\r
+}\r
diff --git a/src/Sample.h b/src/Sample.h
new file mode 100644 (file)
index 0000000..7049f0c
--- /dev/null
@@ -0,0 +1,21 @@
+// Tool functions for getting the data ready to parse (if necessary).\r
+\r
+#include "WAV.h"\r
+\r
+void BuildRawWaveList( struct RAW_Format format, unsigned long offset, double *wavelengthTable, int blocks, bool halfWaves );\r
+double FindNextWavelengthStart( struct RAW_Format format, double pointer );\r
+bool BuildWavelengthTable( struct RAW_Format format, double offset, int blocks, int *wavelengthTable );\r
+double FindWavelength( struct RAW_Format format, double *pointer, bool firstWave, bool preParse, bool fullWave, double *wavelengthTable );\r
+void BuildThresholds( struct RAW_Format format, int thresholds, int *thresholdStore, int *wavelengthTable, int *valueTable );\r
+void BuildRawWaveList_Cleaned( struct RAW_Format format, unsigned long offset, double *wavelengthTable, int blocks,  bool halfWaves );\r
+void AddWave( double *list, int amount, double cycles );\r
+unsigned long ConvertToCycles( double samples );\r
+double ConvertFromCycles( int cycles );\r
+double ConvertFromCyclesToSeconds( int cycles );\r
+\r
+#define NUMBER_OF_THRESHOLDS (20 * 1024)\r
+\r
+extern unsigned int gWaveLengthTable[ NUMBER_OF_THRESHOLDS ];\r
+extern signed int gSample_ValueTable[ NUMBER_OF_THRESHOLDS ];\r
+extern int gThresholds[ 3 ];\r
+static const int gHeaderCheckSize = 60;\r
diff --git a/src/Spectrum.c b/src/Spectrum.c
new file mode 100644 (file)
index 0000000..f582355
--- /dev/null
@@ -0,0 +1,401 @@
+/* Handler for Spectrum tapes. */\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+\r
+#include <math.h>\r
+\r
+#include "UberCassette.h"\r
+#include "WAV.h"\r
+#include "Sample.h"\r
+#include "Spectrum.h"\r
+\r
+#define MAX_WAVELENGTH 20000\r
+\r
+void Spectrum_BuildTapeBlocks( struct RAW_Format format );\r
+struct Spectrum_CassetteBlock *Spectrum_FindTapeBlock( struct RAW_Format format, unsigned long *pointer );\r
+\r
+struct Spectrum_CassetteBlock *gSpectrum_CassetteBlockList = NULL;\r
+\r
+unsigned char *Spectrum_ParseWAV( unsigned char *wavData )\r
+{\r
+       unsigned char *tParsedData = NULL;\r
+       struct RAW_Format tRawData;\r
+\r
+       // First off, extract the RAW data.\r
+       tRawData = WAV_GetRAW( wavData, false );\r
+\r
+    if ( tRawData.data == NULL )\r
+        return NULL;\r
+\r
+       // First we scan the entire file for the wavelength of the header.\r
+       if ( gAlgorithmType == TRIGGER )\r
+               BuildRawWaveList( tRawData, 0, NULL, -1, true );\r
+       else \r
+               BuildRawWaveList_Cleaned( tRawData, 0, NULL, -1, true );\r
+\r
+       if ( gOutputType != CSW )\r
+               Spectrum_BuildTapeBlocks( tRawData );\r
+\r
+       return (unsigned char *)1; // We have data ... but it's somewhere else.\r
+}\r
+\r
+\r
+void Spectrum_BuildTapeBlocks( struct RAW_Format format )\r
+{\r
+#define SBTB_RETRIES 20\r
+\r
+       int tPointer = 0, tDataStartPointer;\r
+       int *tRawPointer = &gRawCycles[ tPointer ], *tDataStartRawPointer;\r
+       double *tWavePointer = &gWaveCycles[ tPointer ], *tDataStartWavePointer;\r
+       int tBlockThresholds[ 3 ]={0,0,0}, tBlockWavelengths[ NUMBER_OF_THRESHOLDS ], tValueTable[ NUMBER_OF_THRESHOLDS ], tCPUThresholds[ 3 ];\r
+       double tOffset = 0.0f, tDataStartOffset;\r
+       int tDelayCounter = 0;\r
+       int tHeaderCycles = 0;\r
+       enum Stage { SS_HEADER, SS_SYNC1, SS_SYNC2, SS_DATA } tStage = SS_HEADER;\r
+       unsigned char tData[ 128 * 1024 ];\r
+       int tDataSize = 0, tBit, tPulse;\r
+       unsigned char tXORByte = 0;\r
+       double tDivisors[ 2 ];\r
+       int tRetry = SBTB_RETRIES;\r
+       bool tDataInvalid = true;\r
+       unsigned short tDataBlockLength = 0;\r
+       struct LoaderStruct tLoader;\r
+\r
+       tDivisors[ 0 ] = gThresholdDivisor[ 0 ];\r
+       tDivisors[ 1 ] = gThresholdDivisor[ 1 ];\r
+\r
+       tLoader.id = LOADER_ROM; \r
+       tLoader.bitsInLastByte = 8;\r
+\r
+       while ( tPointer < gRawLength && tOffset < gRAWFormat.size && *tRawPointer > 0 && *tWavePointer > 0 )\r
+       {\r
+               // What waves are used in this block?\r
+               if ( *tRawPointer >= MAX_WAVELENGTH || BuildWavelengthTable( format, tOffset, 1, tBlockWavelengths ) == false )\r
+               {\r
+                       // Silence is golden.\r
+                       tDelayCounter += *tRawPointer++;\r
+                       tOffset += *tWavePointer++;\r
+               }\r
+               else\r
+               {\r
+                       printf( "Adding data at %f.\n", tOffset );\r
+\r
+                       if ( tDelayCounter > 0 )\r
+                       {\r
+                               if ( tDataSize )\r
+                               {\r
+                                       if ( tLoader.id == LOADER_ROM )\r
+                                               Spectrum_AddStandardDataBlock( format, tDataSize, (char *)tData, tDelayCounter );\r
+                                       else if ( tLoader.id == LOADER_SPEEDLOCK )\r
+                                               Spectrum_AddPureDataBlock( tDataSize, (char *)tData, tDelayCounter, tLoader );\r
+                                       else\r
+                                               Spectrum_AddTurboDataBlock( format, tLoader, tDataSize, (char *)tData, tDelayCounter );\r
+                               }\r
+                               else\r
+                                       Spectrum_AddPauseBlock( format, tDelayCounter );\r
+                               tDelayCounter = 0;\r
+                       }\r
+\r
+                       tDataInvalid = true;\r
+                       tRetry = SBTB_RETRIES;\r
+                       tDataStartOffset = tOffset;\r
+                       tDataStartRawPointer = tRawPointer;\r
+                       tDataStartPointer = tPointer;\r
+                       tDataStartWavePointer = tWavePointer;\r
+\r
+               if ( tOffset == 1720361 )\r
+               {\r
+                       bool test=true;\r
+               }\r
+\r
+                       while ( tRetry > 0 && tDataInvalid )\r
+                       {\r
+                               tXORByte = 0x00;\r
+                               tDataSize = 0; tBit = 0; *tData = 0; tPulse = 0; tStage = SS_HEADER;\r
+\r
+                               // Work out our thresholds....\r
+                               BuildThresholds( format, 3, &tBlockThresholds[ 0 ], tBlockWavelengths, tValueTable );\r
+\r
+                               tCPUThresholds[ 0 ] = ConvertToCycles( tBlockThresholds[ 0 ]); tCPUThresholds[ 1 ] = ConvertToCycles( tBlockThresholds[ 1 ] ); tCPUThresholds[ 2 ] = ConvertToCycles( tBlockThresholds[ 2 ] );\r
+\r
+                               if ( tCPUThresholds[ 0 ] < 1400 && tCPUThresholds[ 1 ] < 2300 && tCPUThresholds[ 2 ] > 3900 ) \r
+                               {\r
+                                       // Work out our protection scheme here.\r
+                                       tLoader.id = LOADER_SPEEDLOCK;\r
+                                       tLoader.bitsInLastByte = 6;     // First 6 bits are ID.\r
+                                       tLoader.zeroPulse = /*0x0234;*/ tCPUThresholds[ 0 ] / 2;\r
+                                       tLoader.onePulse = /*0x0469;*/tCPUThresholds[ 1 ] / 2;\r
+                                       tLoader.pilotLength = 0;\r
+                                       tLoader.sync1 = 3500;\r
+                                       tLoader.sync2 = 0;\r
+                                       tLoader.pilotPulse = /*0x0875*/2168;\r
+                               }\r
+                               if ( tBlockThresholds[ 2 ] == -1 )\r
+                               {\r
+                                       bool test=true;\r
+                               }\r
+\r
+                               // Find our header sync length\r
+\r
+                               while ( tPointer < gRawLength && *tRawPointer < MAX_WAVELENGTH )\r
+                               {\r
+                                       if ( tStage == SS_HEADER )\r
+                                       {\r
+       //                                      if ( tValueTable[ *tRawPointer * 2 ] == 2 )\r
+                                               if ( fabs(*tRawPointer - 2168.0f) < 500.0f )\r
+                                               {\r
+                                                       // We're in standard header timing.\r
+                                                       tHeaderCycles++;\r
+                                                       tLoader.pilotLength++;\r
+                                               }\r
+                                               else if ( tHeaderCycles > 10 )\r
+                                               {\r
+                                                       tStage = SS_SYNC1;\r
+                                                       printf( "Starting data with pulse lengths %d (%ld) and %d(%ld).\n", tBlockThresholds[ 0 ], ConvertToCycles( tBlockThresholds[ 0 ] ), tBlockThresholds[ 1 ], ConvertToCycles( tBlockThresholds [ 1 ]) );\r
+\r
+                                                       continue; // Go back and check this cycle.\r
+                                               }\r
+                                       }\r
+                                       else if ( tStage == SS_SYNC1 )\r
+                                       {\r
+                                               if ( fabs(*tRawPointer - 667.0f) < 800.0f )\r
+                                               {\r
+                                                       if ( tLoader.id == LOADER_ROM )\r
+                                                               tStage = SS_SYNC2;\r
+                                                       else if ( tLoader.id == LOADER_SPEEDLOCK )\r
+                                                       {\r
+                                                               tStage = SS_HEADER;\r
+                                                               printf( "Header blip at %f. Cycles: %d\n", tOffset, tLoader.pilotLength );\r
+                                                               Spectrum_AddPureToneBlock( /*0x0875*/ tCPUThresholds[ 2 ] / 2, tLoader.pilotLength );\r
+                                                               Spectrum_AddPulseBlock( 2, /*0x02CA*/667 );\r
+                                                               tHeaderCycles = 0;\r
+                                                               tLoader.pilotLength = 1;\r
+                                                       }\r
+                                               }\r
+                                               else\r
+                                               {\r
+                                                       if ( tLoader.id == LOADER_SPEEDLOCK )\r
+                                                       {\r
+                                                               if ( *tRawPointer > 0x0C51/*3500*/ )\r
+                                                               {\r
+                                                                       tLoader.pilotLength--;\r
+                                                                       Spectrum_AddPureToneBlock( /*0x0875*/ tCPUThresholds[ 2 ] / 2, tLoader.pilotLength );\r
+                                                                       Spectrum_AddPulseBlock( 2, 0x0C51 /*3663*/ );\r
+                                                                       tStage = SS_DATA;\r
+                                                                       tDataBlockLength = 1; // Just 6 bits, in fact.\r
+                                                               }\r
+                                                       }\r
+                                                       else\r
+                                                       {\r
+                                                               tStage = SS_DATA;\r
+                                                       }\r
+                                               }\r
+                                       }\r
+                                       else if ( tStage == SS_SYNC2 )\r
+                                       {\r
+                                               if ( fabs(*tRawPointer - 735.0f) < 800.0f )\r
+                                               {\r
+                                                       tStage = SS_DATA;\r
+                                               }\r
+                                               else\r
+                                               {\r
+                                                       tStage = SS_DATA;\r
+                                               }\r
+                                       }\r
+                                       else if ( tStage == SS_DATA )\r
+                                       {\r
+                                               if ( tPulse == 0 )\r
+                                                       tPulse = *tRawPointer;\r
+                                               else\r
+                                               {\r
+                                                       tPulse += *tRawPointer;\r
+                                                       tData[ tDataSize ] <<= 1;\r
+                                                       if ( tValueTable[ tPulse ] == 1 )\r
+                                                               tData[ tDataSize ] |= 1;\r
+                                                       else if ( tValueTable[ tPulse ] == 0 )\r
+                                                               tData[ tDataSize ] |= 0;\r
+                                                       tBit++;\r
+                                                       if ( tBit == 8 || (tDataSize == (tDataBlockLength-1) && tBit == tLoader.bitsInLastByte) )\r
+                                                       {\r
+                                                               if ( tDataSize < tDataBlockLength )\r
+                                                               {\r
+                                                                       tXORByte ^= tData[ tDataSize ];\r
+                                                               }\r
+                                                               tData[ tDataSize ] <<= (8 - tLoader.bitsInLastByte);\r
+                                                               tDataSize++;\r
+                                                               tData[ tDataSize ] = 0;\r
+                                                               tBit = 0;\r
+                                                               if ( tLoader.id == LOADER_SPEEDLOCK && tDataSize == tDataBlockLength )\r
+                                                               {\r
+                                                                       Spectrum_AddPureDataBlock( tDataSize, (char *)tData, 0x0000, tLoader );\r
+                                                                       tLoader.bitsInLastByte = 8;\r
+                                                                       tDataSize = 0;\r
+                                                               }\r
+                                                               tDataBlockLength = 0;   // We've done all that data.\r
+                                                       }\r
+                                                       tPulse = 0;\r
+                                               }\r
+                                               tDelayCounter = 0;\r
+                                       }\r
+\r
+                                       tOffset += *tWavePointer;\r
+                                       tPointer++;\r
+                                       tRawPointer++;\r
+                                       tWavePointer++;\r
+                               }\r
+                               if ( tData[ 0 ] == 0x00 )\r
+                               {\r
+                                       // This is a header.\r
+                                       tDataBlockLength = tData[ 11 ] + tData[ 12 ] * 256;\r
+                               }\r
+                               if ( tLoader.id == LOADER_ROM )\r
+                               {\r
+                                       if ( tXORByte != 0x00 )\r
+                                       {\r
+                                               printf(" WARNING! Invalid XOR checksum.\n" );\r
+               \r
+                                               if ( --tRetry )\r
+                                               {\r
+                                                       double tThresholdMod;\r
+                                                       printf(" Retrying...\n" );\r
+                                                       tThresholdMod = 0.025f * (float)((SBTB_RETRIES - (tRetry - 1) ) / 2) * ( (tRetry & 1) ? +1 : -1 );\r
+                                                       gThresholdDivisor[ 0 ] = tDivisors[ 0 ] + tThresholdMod;\r
+                                                       gThresholdDivisor[ 1 ] = tDivisors[ 1 ] + tThresholdMod;\r
+                                                       tOffset = tDataStartOffset;\r
+                                                       tRawPointer = tDataStartRawPointer ;\r
+                                                       tPointer = tDataStartPointer;\r
+                                                       tWavePointer = tDataStartWavePointer;\r
+                                               }\r
+                                               else\r
+                                                       printf( "Giving up.\n" );\r
+                                       }\r
+                                       else\r
+                                               tDataInvalid = false;\r
+                               }\r
+                               else\r
+                                       tDataInvalid = false;\r
+                       }\r
+               }\r
+       }\r
+       if ( tDataSize )\r
+       {\r
+               if ( tLoader.id == LOADER_ROM )\r
+                       Spectrum_AddStandardDataBlock( format, tDataSize, (char *)tData, tDelayCounter );\r
+               else if ( tLoader.id == LOADER_SPEEDLOCK )\r
+                       Spectrum_AddPureDataBlock( tDataSize, (char *)tData, tDelayCounter, tLoader );\r
+               else\r
+                       Spectrum_AddTurboDataBlock( format, tLoader, tDataSize, (char *)tData, tDelayCounter );\r
+       }\r
+\r
+       gThresholdDivisor[ 0 ] = tDivisors[ 0 ];\r
+       gThresholdDivisor[ 1 ] = tDivisors[ 1 ];\r
+}\r
+\r
+void Spectrum_ReadData( unsigned char *data, int length, struct RAW_Format format, unsigned long *pointer )\r
+{\r
+}\r
+\r
+\r
+struct SpectrumHeader Spectrum_ReadHeader( struct RAW_Format format, unsigned long *pointer )\r
+{\r
+       struct SpectrumHeader tHeader;\r
+       tHeader.startAddress = 0;\r
+       tHeader.endAddress = 0;\r
+       *tHeader.name = 0;\r
+       return tHeader; \r
+}\r
+\r
+struct Spectrum_CassetteBlock *Spectrum_FindTapeBlock( struct RAW_Format format, unsigned long *pointer )\r
+{\r
+       return NULL;\r
+\r
+}\r
+\r
+unsigned long Spectrum_FindHeader( struct RAW_Format format, unsigned long pointer )\r
+{\r
+       return 0;\r
+}\r
+\r
+void Spectrum_AddBlock( enum Spectrum_CassetteBlockType type, int cycles, char *data, int pause, struct LoaderStruct *loader )\r
+{\r
+       struct Spectrum_CassetteBlock *tNode = gSpectrum_CassetteBlockList;\r
+\r
+       while ( tNode )\r
+       {\r
+               if ( tNode->next )\r
+                       tNode = tNode->next;\r
+               else\r
+                       break;\r
+       }\r
+\r
+       if ( tNode && tNode->type == SCBT_PULSE && type == SCBT_PULSE )\r
+       {\r
+               bool test=true;\r
+       }\r
+\r
+\r
+       if ( gSpectrum_CassetteBlockList == NULL )\r
+               tNode = gSpectrum_CassetteBlockList = (struct Spectrum_CassetteBlock *)malloc( sizeof( struct Spectrum_CassetteBlock ) );\r
+       else\r
+       {\r
+               tNode->next = (struct Spectrum_CassetteBlock *)malloc( sizeof( struct Spectrum_CassetteBlock ) );\r
+               tNode = tNode->next;\r
+       }\r
+\r
+\r
+       tNode->type = type;\r
+       tNode->size = cycles;\r
+       tNode->data = (unsigned char *)data;\r
+       tNode->pause = pause;\r
+       if ( loader )\r
+       {\r
+               tNode->loader = (struct LoaderStruct *)malloc( sizeof( struct LoaderStruct ));\r
+               if ( tNode->loader == NULL )\r
+               {\r
+                       printf( "WARNING: Out of memory copying loader info.\n" );\r
+               }\r
+               else\r
+                       memcpy( tNode->loader, loader, sizeof( struct LoaderStruct ));\r
+       }\r
+       tNode->next = NULL;\r
+}\r
+\r
+void Spectrum_AddPauseBlock( struct RAW_Format format, int cycles )\r
+{\r
+       Spectrum_AddBlock( SCBT_PAUSE, cycles, NULL, 0, NULL );\r
+}\r
+\r
+void Spectrum_AddStandardDataBlock( struct RAW_Format format, int length, char *data, int pause )\r
+{\r
+       unsigned char *tData = (unsigned char *)malloc(length);\r
+       memcpy( tData, data, length );\r
+       Spectrum_AddBlock( SCBT_DATA, length, (char *)tData, pause, NULL );\r
+}\r
+\r
+void Spectrum_AddTurboDataBlock( struct RAW_Format format, struct LoaderStruct loader, int length, char *data, int pause )\r
+{\r
+       unsigned char *tData = (unsigned char *)malloc(length);\r
+       memcpy( tData, data, length );\r
+\r
+       Spectrum_AddBlock( SCBT_TURBODATA, length, (char *)tData, pause, &loader );\r
+\r
+}\r
+\r
+void Spectrum_AddPureToneBlock( int pulseLength, int count )\r
+{\r
+       Spectrum_AddBlock( SCBT_TONE, count, NULL, pulseLength, NULL );\r
+}\r
+\r
+void Spectrum_AddPulseBlock( int pulseLength, int count )\r
+{\r
+       Spectrum_AddBlock( SCBT_PULSE, count, NULL, pulseLength, NULL );\r
+}\r
+\r
+void Spectrum_AddPureDataBlock( int length, char *data, int pause, struct LoaderStruct loader )\r
+{\r
+       unsigned char *tData = (unsigned char *)malloc(length);\r
+       memcpy( tData, data, length );\r
+\r
+       Spectrum_AddBlock( SCBT_PUREDATA, length, (char *)tData, pause, &loader );\r
+}\r
diff --git a/src/Spectrum.h b/src/Spectrum.h
new file mode 100644 (file)
index 0000000..e88c2fc
--- /dev/null
@@ -0,0 +1,53 @@
+/* The WAV handler for Spectrum tapes. */\r
+\r
+#ifndef __SPECTRUM_H__\r
+#define __SPECTRUM_H__\r
+\r
+#include "WAV.h"\r
+\r
+enum Spectrum_CassetteBlockType { SCBT_HEADER, SCBT_DUMMYBYTE, SCBT_DATA, SCBT_TURBODATA, SCBT_PAUSE, SCBT_TONE, SCBT_PULSE, SCBT_PUREDATA };\r
+\r
+struct LoaderStruct\r
+{\r
+       enum Loader id;\r
+       int pilotPulse;\r
+       int zeroPulse;\r
+       int onePulse;\r
+       int sync1;\r
+       int sync2;\r
+       int pilotLength;\r
+       int bitsInLastByte;\r
+};\r
+\r
+struct Spectrum_CassetteBlock\r
+{\r
+       enum Spectrum_CassetteBlockType type;\r
+       unsigned char *data;\r
+       int size;\r
+       int pause;      // Delay after this block in mS.\r
+       struct LoaderStruct *loader;\r
+       struct Spectrum_CassetteBlock *next;\r
+};\r
+\r
+struct SpectrumHeader\r
+{\r
+       unsigned short startAddress;\r
+       unsigned short endAddress;\r
+       char name[ 128 ];\r
+};\r
+\r
+\r
+\r
+extern struct Spectrum_CassetteBlock *gSpectrum_CassetteBlockList;\r
+\r
+unsigned char *Spectrum_ParseWAV( unsigned char *rawData );\r
+unsigned long Spectrum_FindHeader( struct RAW_Format format, unsigned long pointer );\r
+void Spectrum_AddPauseBlock( struct RAW_Format format, int cycles );\r
+void Spectrum_AddStandardDataBlock( struct RAW_Format format, int length, char *data, int pause );\r
+void Spectrum_AddPureDataBlock( int length, char *data, int pause, struct LoaderStruct loader );\r
+void Spectrum_AddTurboDataBlock( struct RAW_Format format, struct LoaderStruct loader, int length, char *data, int pause );\r
+void Spectrum_AddBlock( enum Spectrum_CassetteBlockType type, int cycles, char *data, int pause, struct LoaderStruct *loader );\r
+void Spectrum_AddPureToneBlock( int pulseLength, int count );\r
+void Spectrum_AddPulseBlock( int pulseLength, int count );\r
+\r
+#endif\r
diff --git a/src/T64.c b/src/T64.c
new file mode 100644 (file)
index 0000000..0f71fee
--- /dev/null
+++ b/src/T64.c
@@ -0,0 +1,107 @@
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+\r
+#include "UberCassette.h"\r
+\r
+#include "CBM.h"\r
+\r
+struct T64_TapeInfo\r
+{\r
+       unsigned short version;\r
+       unsigned short maxEntries;\r
+       unsigned short usedEntries;\r
+       unsigned char pad[ 2 ];\r
+       char name[ 25 ];        // Terminating zero on the end.\r
+};\r
+\r
+struct T64_DirectoryEntry\r
+{\r
+       unsigned char fileType;\r
+       unsigned char diskFileType;\r
+       unsigned short startAddress;\r
+       unsigned short endAddress;\r
+       unsigned char pad[ 2 ];\r
+       unsigned long offset;\r
+       unsigned char pad2[ 4 ];\r
+       unsigned char filename[ 16 ];\r
+};\r
+\r
+void T64_WriteHeader( FILE *file, struct CBM_CassetteBlock *list )\r
+{\r
+       int tEntries = 0, i;\r
+       struct CBM_CassetteBlock *tNode = list;\r
+       char tBuffer[ 33 ];\r
+       struct T64_TapeInfo *tTapeInfo;\r
+       struct T64_DirectoryEntry *tDirectoryEntry;\r
+       unsigned long tOffset = 0;\r
+\r
+       while ( tNode )\r
+       {\r
+               tNode = tNode->next;\r
+               tEntries++;\r
+       }\r
+\r
+       memset( tBuffer, 0, 32 );\r
+       sprintf( tBuffer, "C64S tape image file" );\r
+       fwrite( tBuffer, 32, 1, file );\r
+\r
+       memset( tBuffer, 0, 32 );\r
+       tTapeInfo = ( struct T64_TapeInfo *)tBuffer;\r
+       tTapeInfo->version = 0x0101;\r
+       tTapeInfo->maxEntries = CorrectEndianShort( tEntries );\r
+       tTapeInfo->usedEntries = CorrectEndianShort( tEntries );\r
+       sprintf( tTapeInfo->name, "DUMPED TAPE             " );\r
+       fwrite( tBuffer, 32, 1, file );\r
+\r
+       tOffset = 0x40 + 0x20 * tEntries;\r
+       tDirectoryEntry = (struct T64_DirectoryEntry *)tBuffer;\r
+\r
+       tNode = list;\r
+\r
+       while ( tNode )\r
+       {\r
+               memset( tBuffer, 0x20, 32 );\r
+               tDirectoryEntry->fileType = tNode->c64sFileType;\r
+               tDirectoryEntry->diskFileType = tNode->cbm1541FileType;\r
+               tDirectoryEntry->startAddress = CorrectEndianShort( tNode->startAddress );\r
+               tDirectoryEntry->endAddress = CorrectEndianShort( tNode->endAddress );\r
+               tDirectoryEntry->offset = CorrectEndianLong( tOffset );\r
+               tOffset += tNode->endAddress - tNode->startAddress + 1;\r
+               for ( i=0 ; i<16 ; i++ )\r
+                       tDirectoryEntry->filename[ i ] = tNode->filename[ i ];\r
+\r
+               fwrite( tBuffer, 32, 1, file );\r
+               tNode = tNode->next;\r
+       }\r
+}\r
+\r
+void T64_WriteBlocks( FILE *file, struct CBM_CassetteBlock *list )\r
+{\r
+       struct CBM_CassetteBlock *tNode = list;\r
+\r
+       while ( tNode )\r
+       {\r
+               fwrite( tNode->data, 1, tNode->endAddress - tNode->startAddress + 1, file );\r
+        free( tNode->data );\r
+               tNode = tNode->next;\r
+       }\r
+}\r
+\r
+void T64_Output( struct CBM_CassetteBlock *list, char *filename )\r
+{\r
+       FILE *tOutputFile = NULL;\r
+       struct CBM_CassetteBlock *tBlock = list;\r
+\r
+       tOutputFile = fopen( filename, "wb" );\r
+       if ( tOutputFile == NULL )\r
+       {\r
+               printf( "Couldn't open output file.\n" );\r
+               return;\r
+       }\r
+\r
+       T64_WriteHeader( tOutputFile, gCBM_CassetteBlockList );\r
+       T64_WriteBlocks( tOutputFile, gCBM_CassetteBlockList );                 \r
+\r
+       fclose( tOutputFile );\r
+}\r
diff --git a/src/T64.h b/src/T64.h
new file mode 100644 (file)
index 0000000..f7cedd7
--- /dev/null
+++ b/src/T64.h
@@ -0,0 +1 @@
+void T64_Output( struct CBM_CassetteBlock *list, char *filename );\r
diff --git a/src/TAP.c b/src/TAP.c
new file mode 100644 (file)
index 0000000..360d9d1
--- /dev/null
+++ b/src/TAP.c
@@ -0,0 +1,145 @@
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+\r
+#include "UberCassette.h"\r
+\r
+#include "CBM.h"\r
+\r
+struct TAP_TapeInfo\r
+{\r
+       char identifier[ 12 ];\r
+       unsigned char version;\r
+       unsigned char machineID;\r
+       unsigned char videoType;\r
+       unsigned char pad[ 1 ];\r
+       unsigned long length;\r
+       unsigned char data[0];\r
+};\r
+\r
+\r
+void TAP_WriteHeader( FILE *file, int *data, unsigned long length )\r
+{\r
+       char tBuffer[ 20 ];\r
+       struct TAP_TapeInfo *tTapeInfo = (struct TAP_TapeInfo *)tBuffer;\r
+       int tByteLength = 0;\r
+       unsigned long tPointer = 0;\r
+       unsigned long tCycles;\r
+\r
+       while ( tPointer < length )\r
+       {\r
+               tCycles = data[ tPointer ];\r
+               if ( (tCycles / 8) > 0xFF )\r
+                       tByteLength += 3;\r
+               tByteLength++;\r
+               tPointer++;\r
+       }\r
+\r
+       memset( tTapeInfo, 0, 20 );\r
+       sprintf( tTapeInfo->identifier, "%s-TAPE-RAW", gMachineData.string );\r
+\r
+       tTapeInfo->version = (gMachineData.halfWave ? 2 : 1); // Half-waves for C16.\r
+       tTapeInfo->machineID = gMachineData.machineID;\r
+       tTapeInfo->length = tByteLength;\r
+       tTapeInfo->videoType = gVideoType;\r
+\r
+       fwrite( tTapeInfo, 20, 1, file );\r
+}\r
+\r
+void TAP_WriteBlocks( FILE *file, int *data, unsigned long length )\r
+{\r
+       unsigned long tPointer = 0;\r
+       unsigned long tCycles;\r
+       unsigned char tBuffer[ 4 ];\r
+       //signed char tDistances[ 3 ];\r
+\r
+       while ( tPointer < length )\r
+       {\r
+               tCycles = data[ tPointer ];\r
+               if ( (tCycles / 8) > 0xFF )\r
+               {\r
+                       tBuffer[ 0 ] = 0x00;\r
+                       tBuffer[ 1 ]= tCycles & 0xFF;\r
+                       tBuffer[ 2 ]= (unsigned char )((tCycles & 0xFF00) >> 8);\r
+                       tBuffer[ 3 ]= (unsigned char )((tCycles & 0xFF0000) >> 16);\r
+                       fwrite( tBuffer, 4, 1, file );\r
+               }\r
+               else\r
+               {\r
+/*                     tCycles /= 8;\r
+                       tDistances[ 0 ] = (signed char )abs(tCycles - 0x2C); \r
+                       tDistances[ 1 ] = (signed char )abs(tCycles - 0x3F); \r
+                       tDistances[ 2 ] = (signed char )abs(tCycles - 0x55); \r
+\r
+                       if ( tDistances[ 0 ] <= tDistances[ 1 ] && tDistances[ 0 ] <= tDistances[ 2 ] )\r
+                               tBuffer[ 0 ] = 0x2C;\r
+                       else if ( tDistances[ 1 ] <= tDistances[ 0 ] && tDistances[ 1 ] <= tDistances[ 2 ] )\r
+                               tBuffer[ 0 ] = 0x3F;\r
+                       else if ( tDistances[ 2 ] <= tDistances[ 0 ] && tDistances[ 2 ] <= tDistances[ 1 ] )\r
+                               tBuffer[ 0 ] = 0x55;\r
+*/\r
+\r
+                       if ( tCycles >= 8 )\r
+                       {\r
+                               tBuffer[ 0 ] = (unsigned char )(tCycles / 8);\r
+                               fwrite( tBuffer, 1, 1, file );\r
+                       }\r
+               }\r
+               tPointer++;\r
+       }\r
+}\r
+\r
+void TAP_Output( struct CBM_CassetteBlock *list, char *filename )\r
+{\r
+       FILE *tOutputFile = NULL;\r
+       struct CBM_CassetteBlock *tBlock = list;\r
+\r
+       unsigned long tLength = gRawLength;\r
+\r
+    printf( "Writing TAP file.\n" );\r
+\r
+       tOutputFile = fopen( filename, "wb" );\r
+       if ( tOutputFile == NULL )\r
+       {\r
+               printf( "Couldn't open output file.\n" );\r
+               return;\r
+       }\r
+\r
+       TAP_WriteHeader( tOutputFile, gRawCycles, tLength );\r
+       TAP_WriteBlocks( tOutputFile, gRawCycles, tLength );                    \r
+\r
+       fclose( tOutputFile );\r
+       \r
+       printf( "Written TAP file.\n" );\r
+}\r
+\r
+unsigned char *TAP_Parse( unsigned char *data, int size )\r
+{\r
+       int tIndex = 0;\r
+       unsigned char *tPointer = data;\r
+\r
+       tIndex = sizeof( struct TAP_TapeInfo );\r
+       tPointer = &data[ tIndex ];\r
+\r
+       for ( tIndex = 0 ; tIndex < size ; tIndex++ )\r
+       {\r
+               if ( *tPointer == 0x00 )\r
+               {\r
+                       int tDelay = 0x00000000;\r
+\r
+                       tDelay = *(tPointer+1);\r
+                       tDelay += *(tPointer+2) << 8;\r
+                       tDelay += *(tPointer+3) << 16;\r
+                       tPointer += 3;\r
+\r
+                       AddMachineCycle( tDelay );\r
+               }\r
+               else\r
+               {\r
+                       AddMachineCycle( *tPointer * 8 );       \r
+               }\r
+\r
+               tPointer++;\r
+       }\r
+       return (unsigned char *)1;\r
+}\r
diff --git a/src/TAP.h b/src/TAP.h
new file mode 100644 (file)
index 0000000..3b1e7d2
--- /dev/null
+++ b/src/TAP.h
@@ -0,0 +1,2 @@
+void TAP_Output( struct CBM_CassetteBlock *list, char *filename );\r
+unsigned char *TAP_Parse( unsigned char *data, int size );\r
diff --git a/src/TZX.c b/src/TZX.c
new file mode 100644 (file)
index 0000000..45bd3da
--- /dev/null
+++ b/src/TZX.c
@@ -0,0 +1,288 @@
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+\r
+#include "UberCassette.h"\r
+#include "Sample.h"\r
+\r
+#include "Spectrum.h"\r
+\r
+#define SAMPLE_RATE 44100 * 4\r
+\r
+struct TZX_TZXInfo\r
+{\r
+       char identifier[ 8 ];\r
+       unsigned char majorRevision;\r
+       unsigned char minorRevision;\r
+};\r
+\r
+struct TZX_CSWInfo\r
+{\r
+       unsigned long length;\r
+       unsigned short pause;\r
+       unsigned char sampleRate[ 3 ];\r
+       unsigned char compression;\r
+       unsigned long pulses;\r
+};\r
+\r
+void TZX_WriteHeader( FILE *file, int *data, unsigned long length )\r
+{\r
+       struct TZX_TZXInfo tTZXInfo;\r
+       int tByteLength = 0;\r
+       unsigned long tPointer = 0;\r
+\r
+       sprintf( tTZXInfo.identifier, "ZXTape!", gMachineData.string );\r
+       tTZXInfo.identifier[ 7 ] = 0x1A;\r
+\r
+       tTZXInfo.majorRevision = 1;\r
+       tTZXInfo.minorRevision = 20;\r
+\r
+       fwrite( &tTZXInfo, sizeof( struct TZX_TZXInfo ), 1, file );\r
+}\r
+\r
+void TZX_AddDataBlock( struct Spectrum_CassetteBlock *node, FILE *file )\r
+{\r
+       unsigned char tBuffer[ 7 ];\r
+       unsigned short tPauseLength, tDataLength, tBlockLength;\r
+       unsigned char *tPointer = tBuffer;\r
+\r
+       tPauseLength = (unsigned short)(((float)node->pause / (float)gMachineData.speed_PAL) * 1000.0f);\r
+       tDataLength = node->size;\r
+       tBlockLength = 4 + tDataLength;\r
+\r
+       *tPointer++ = 0x10; // Data.\r
+//     tBuffer[ 1 ] = tBlockLength & 0xFF;\r
+//     tBuffer[ 2 ] = (tBlockLength & 0xFF00) >> 8;\r
+       *tPointer++ = tPauseLength & 0xFF;\r
+       *tPointer++ = (tPauseLength & 0xFF00) >> 8;\r
+       *tPointer++ = tDataLength & 0xFF;\r
+       *tPointer++ = (tDataLength & 0xFF00) >> 8;\r
+\r
+       fwrite( tBuffer, tPointer - tBuffer, 1, file );\r
+       fwrite( node->data, tDataLength, 1, file );\r
+       free( node->data );\r
+}\r
+\r
+void TZX_AddPureDataBlock( struct Spectrum_CassetteBlock *node, FILE *file )\r
+{\r
+       unsigned char tBuffer[ 12 ];\r
+       unsigned short tPauseLength, tDataLength, tBlockLength;\r
+       unsigned char *tPointer = tBuffer;\r
+       struct LoaderStruct *tLoader = node->loader;\r
+\r
+       tPauseLength = (unsigned short)(((float)node->pause / (float)gMachineData.speed_PAL) * 1000.0f);\r
+       tDataLength = node->size;\r
+       tBlockLength = 10 + tDataLength;\r
+\r
+       *tPointer++ = 0x14; // Data.\r
+       *tPointer++ = tLoader->zeroPulse & 0xFF;\r
+       *tPointer++ = (tLoader->zeroPulse & 0xFF00) >> 8;\r
+       *tPointer++ = tLoader->onePulse & 0xFF;\r
+       *tPointer++ = (tLoader->onePulse & 0xFF00) >> 8;\r
+       *tPointer++ = tLoader->bitsInLastByte & 0xFF;\r
+       *tPointer++ = tPauseLength & 0xFF;\r
+       *tPointer++ = (tPauseLength & 0xFF00) >> 8;\r
+       *tPointer++ = tDataLength & 0xFF;\r
+       *tPointer++ = (tDataLength & 0xFF00) >> 8;\r
+       *tPointer++ = (tDataLength & 0xFF0000) >> 16;\r
+\r
+       fwrite( tBuffer, tPointer - tBuffer, 1, file );\r
+       fwrite( node->data, tDataLength, 1, file );\r
+       if ( node->loader )\r
+               free( node->loader );\r
+       free( node->data );\r
+}\r
+\r
+\r
+void TZX_AddTurboDataBlock( struct Spectrum_CassetteBlock *node, FILE *file )\r
+{\r
+       unsigned char tBuffer[ 20 ];\r
+       unsigned short tPauseLength, tBlockLength;\r
+       int tDataLength;\r
+       unsigned char *tPointer = tBuffer;\r
+       struct LoaderStruct *tLoader = node->loader;\r
+\r
+       tPauseLength = (unsigned short)(((float)node->pause / (float)gMachineData.speed_PAL) * 1000.0f);\r
+       tDataLength = node->size;\r
+       tBlockLength = 0x12 + tDataLength;\r
+\r
+       *tPointer++ = 0x11; // Data.\r
+       *tPointer++ = tLoader->pilotPulse & 0xFF;\r
+       *tPointer++ = (tLoader->pilotPulse & 0xFF00) >> 8;\r
+       *tPointer++ = tLoader->sync1 & 0xFF;\r
+       *tPointer++ = (tLoader->sync1 & 0xFF00) >> 8;\r
+       *tPointer++ = tLoader->sync2 & 0xFF;\r
+       *tPointer++ = (tLoader->sync2 & 0xFF00) >> 8;\r
+       *tPointer++ = tLoader->zeroPulse & 0xFF;\r
+       *tPointer++ = (tLoader->zeroPulse & 0xFF00) >> 8;\r
+       *tPointer++ = tLoader->onePulse & 0xFF;\r
+       *tPointer++ = (tLoader->onePulse & 0xFF00) >> 8;\r
+       *tPointer++ = tLoader->pilotLength & 0xFF;\r
+       *tPointer++ = (tLoader->pilotLength & 0xFF00) >> 8;\r
+       *tPointer++ = tLoader->bitsInLastByte & 0xFF;\r
+       *tPointer++ = tPauseLength & 0xFF;\r
+       *tPointer++ = (tPauseLength & 0xFF00) >> 8;\r
+       *tPointer++ = tDataLength & 0xFF;\r
+       *tPointer++ = (tDataLength & 0xFF00) >> 8;\r
+       *tPointer++ = (tDataLength & 0xFF0000) >> 16;\r
+\r
+       fwrite( tBuffer, tPointer - tBuffer, 1, file );\r
+       fwrite( node->data, tDataLength, 1, file );\r
+       if ( node->loader )\r
+               free( node->loader );\r
+       free( node->data );\r
+}\r
+\r
+\r
+void TZX_AddPauseBlock( struct Spectrum_CassetteBlock *node, FILE *file )\r
+{\r
+       unsigned char tBuffer[ 6 ], *tPointer;\r
+       unsigned short tLength, tBlockLength;\r
+\r
+       tPointer = tBuffer;\r
+       tLength = (unsigned short)(((float)node->size / (float)gMachineData.speed_PAL) * 1000.0f);\r
+       tBlockLength = 2;\r
+\r
+       *tPointer++ = 0x20; // Pause.\r
+       *tPointer++ = tLength & 0xFF;\r
+       *tPointer++ = (tLength & 0xFF00) >> 8;\r
+\r
+       fwrite( tBuffer, tPointer - tBuffer, 1, file );\r
+       \r
+}\r
+\r
+void TZX_AddPulseBlock( struct Spectrum_CassetteBlock *node, FILE *file )\r
+{\r
+       unsigned char tBuffer[ 6 ], *tPointer;\r
+       unsigned short tLength, tBlockLength, tPulseLength;\r
+       int i;\r
+\r
+       tPointer = tBuffer;\r
+       tLength = node->pause;\r
+       tPulseLength = node->size;\r
+\r
+       tBlockLength = 1 + tLength * 2;\r
+\r
+       *tPointer++ = 0x13; // Pause.\r
+       *tPointer++ = tLength & 0xFF;\r
+\r
+       fwrite( tBuffer, tPointer - tBuffer, 1, file );\r
+\r
+       for ( i=0 ; i<tLength ; i++ )\r
+       {\r
+               tPointer = &tBuffer[ 0 ];\r
+               *tPointer++ = tPulseLength & 0xFF;\r
+               *tPointer++ = (tPulseLength & 0xFF00) >> 8;\r
+               fwrite( tBuffer, tPointer - tBuffer, 1, file );\r
+       }\r
+}      \r
+\r
+void TZX_AddToneBlock( struct Spectrum_CassetteBlock *node, FILE *file )\r
+{\r
+       unsigned char tBuffer[ 6 ], *tPointer;\r
+       unsigned short tLength, tBlockLength, tPulseLength;\r
+\r
+       tPointer = tBuffer;\r
+       tLength = node->size;\r
+       tPulseLength = node->pause;\r
+\r
+       tBlockLength = 1 + tLength * 2;\r
+\r
+       *tPointer++ = 0x12; // Pause.\r
+       *tPointer++ = tPulseLength & 0xFF;\r
+       *tPointer++ = (tPulseLength & 0xFF00) >> 8;\r
+       *tPointer++ = tLength & 0xFF;\r
+       *tPointer++ = (tLength & 0xFF00) >> 8;\r
+\r
+       fwrite( tBuffer, tPointer - tBuffer, 1, file );\r
+}      \r
+\r
+\r
+void TZX_WriteBlocks( struct Spectrum_CassetteBlock *node, FILE *file )\r
+{\r
+       struct Spectrum_CassetteBlock *tNode = node;\r
+\r
+       while ( tNode )\r
+       {\r
+               switch ( tNode->type )\r
+               {\r
+               case SCBT_PULSE:\r
+                       TZX_AddPulseBlock( tNode, file );\r
+                       break;\r
+               case SCBT_TONE:\r
+                       TZX_AddToneBlock( tNode, file );\r
+                       break;\r
+               case SCBT_PAUSE:\r
+                       TZX_AddPauseBlock( tNode, file );\r
+                       break;\r
+               case SCBT_DATA:\r
+                       TZX_AddDataBlock( tNode, file );\r
+                       break;\r
+               case SCBT_TURBODATA:\r
+                       TZX_AddTurboDataBlock( tNode, file );\r
+                       break;\r
+               case SCBT_PUREDATA:\r
+                       TZX_AddPureDataBlock( tNode, file );\r
+                       break;\r
+               default:\r
+                       break;\r
+               }\r
+\r
+               tNode = tNode->next;\r
+       }\r
+}\r
+\r
+void TZX_Output( struct Spectrum_CassetteBlock *list, char *filename )\r
+{\r
+       FILE *tOutputFile = NULL;\r
+       struct Spectrum_CassetteBlock *tBlock = list;\r
+\r
+       unsigned long tLength = gRawLength;\r
+\r
+    printf( "Writing TZX file.\n" );\r
+\r
+       tOutputFile = fopen( filename, "wb" );\r
+       if ( tOutputFile == NULL )\r
+       {\r
+               printf( "Couldn't open output file.\n" );\r
+               return;\r
+       }\r
+\r
+       TZX_WriteHeader( tOutputFile, gRawCycles, tLength );\r
+       TZX_WriteBlocks( gSpectrum_CassetteBlockList, tOutputFile );                    \r
+\r
+       fclose( tOutputFile );\r
+       \r
+       printf( "Written TZX file.\n" );\r
+}\r
+\r
+unsigned char *TZX_Parse( unsigned char *data, int size )\r
+{\r
+       int tIndex = 0;\r
+       unsigned char *tPointer = data;\r
+\r
+       tIndex = sizeof( struct TZX_TZXInfo );\r
+       tPointer = &data[ tIndex ];\r
+\r
+       for ( tIndex = 0 ; tIndex < size ; tIndex++ )\r
+       {\r
+               if ( *tPointer == 0x00 )\r
+               {\r
+                       int tDelay = 0x00000000;\r
+\r
+                       tDelay = *(tPointer+1);\r
+                       tDelay += *(tPointer+2) << 8;\r
+                       tDelay += *(tPointer+3) << 16;\r
+                       tPointer += 3;\r
+\r
+                       AddMachineCycle( tDelay );\r
+               }\r
+               else\r
+               {\r
+                       AddMachineCycle( *tPointer * 8 );       \r
+               }\r
+\r
+               tPointer++;\r
+       }\r
+       return (unsigned char *)1;\r
+}\r
diff --git a/src/TZX.h b/src/TZX.h
new file mode 100644 (file)
index 0000000..984e4fb
--- /dev/null
+++ b/src/TZX.h
@@ -0,0 +1,4 @@
+void TZX_Output( struct Spectrum_CassetteBlock *list, char *filename );\r
+unsigned char *TZX_Parse( unsigned char *data, int size );\r
+void TZX_AddPauseBlock( struct Spectrum_CassetteBlock *node, FILE *file );\r
+\r
diff --git a/src/UEF.c b/src/UEF.c
new file mode 100644 (file)
index 0000000..a15448a
--- /dev/null
+++ b/src/UEF.c
@@ -0,0 +1,121 @@
+#include <stdio.h>\r
+#include <stdlib.h>\r
+\r
+#include "UberCassette.h"\r
+#include "WAV.h"\r
+\r
+#include "Acorn.h"\r
+#include "UEF.h"\r
+\r
+struct UEF_Header\r
+{\r
+       char string[ 10 ];\r
+       unsigned char minorVersion;\r
+       unsigned char majorVersion;\r
+};\r
+\r
+void UEF_WriteHeader( struct Acorn_CassetteBlock *node, FILE *file )\r
+{\r
+       unsigned char tData[ 20 ];\r
+\r
+       tData[ 0 ] = 0x10;\r
+       tData[ 1 ] = 0x01;\r
+       tData[ 2 ] = 0x02;\r
+       tData[ 3 ] = 0x00;\r
+       tData[ 4 ] = 0x00;\r
+       tData[ 5 ] = 0x00;\r
+       tData[ 6 ] = (node->sizeUnion.size) & 0xFF;\r
+       tData[ 7 ] = (node->sizeUnion.size >> 8) & 0xFF;\r
+       fwrite( tData, 8, 1, file );\r
+}\r
+\r
+void UEF_WriteDummy( struct Acorn_CassetteBlock *node, FILE *file )\r
+{\r
+       unsigned char tData[ 20 ];\r
+\r
+       tData[ 0 ] = 0x11;\r
+       tData[ 1 ] = 0x01;\r
+       tData[ 2 ] = 0x04;\r
+       tData[ 3 ] = 0x00;\r
+       tData[ 4 ] = 0x00;\r
+       tData[ 5 ] = 0x00;\r
+       tData[ 6 ] = 0x03;\r
+       tData[ 7 ] = 0x00;\r
+       tData[ 8 ] = (node->sizeUnion.size ) & 0xFF;\r
+       tData[ 9 ] = (node->sizeUnion.size >> 8) & 0xFF;\r
+       fwrite( tData, 10, 1, file );\r
+}\r
+\r
+\r
+void UEF_WritePause( struct Acorn_CassetteBlock *node, FILE *file )\r
+{\r
+       unsigned char tData[ 20 ];\r
+    unsigned long *tLengthBytes = (unsigned long *)&tData[ 6 ];\r
+\r
+    *tLengthBytes = ConvertTo8087Float( node->sizeUnion.seconds );\r
+\r
+       tData[ 0 ] = 0x16;\r
+       tData[ 1 ] = 0x01;\r
+       tData[ 2 ] = 0x04;\r
+       tData[ 3 ] = 0x00;\r
+       tData[ 4 ] = 0x00;\r
+       tData[ 5 ] = 0x00;\r
+       fwrite( tData, 10, 1, file );\r
+}\r
+\r
+void UEF_WriteData( struct Acorn_CassetteBlock *node, FILE *file )\r
+{\r
+       unsigned char tData[ 20 ];\r
+\r
+ //   printf( "Writing UEF data node of size %ld.\n", node->size );\r
+\r
+       tData[ 0 ] = 0x00;\r
+       tData[ 1 ] = 0x01;\r
+       *((int*)&tData[ 2 ]) = CorrectEndianLong( node->sizeUnion.size );\r
+       fwrite( tData, 6, 1, file );\r
+       fwrite( node->data, 1, node->sizeUnion.size, file );\r
+       free( node->data );\r
+}\r
+\r
+void UEF_Output( struct Acorn_CassetteBlock *list, char *filename )\r
+{\r
+       unsigned char tData[ 20 ];\r
+       struct UEF_Header *tHeader = (struct UEF_Header *)tData;\r
+       FILE *tFile;\r
+       struct Acorn_CassetteBlock *tNode = gAcorn_CassetteBlockList, *tOldNode;\r
+\r
+       tFile = fopen( filename, "wb" );\r
+       if ( tFile == NULL )\r
+               return;\r
+\r
+       sprintf( tHeader->string, "UEF File!" );\r
+       tHeader->minorVersion = 10;\r
+       tHeader->majorVersion = 0;\r
+\r
+       fwrite( tHeader, sizeof( struct UEF_Header ), 1, tFile );\r
+\r
+       while ( tNode != NULL )\r
+       {\r
+               switch ( tNode->type )\r
+               {\r
+               case ACBT_HEADER:\r
+                       UEF_WriteHeader( tNode, tFile );\r
+                       break;\r
+               case ACBT_DUMMYBYTE:\r
+                       UEF_WriteDummy( tNode, tFile );\r
+                       break;\r
+               case ACBT_DATA:\r
+                       UEF_WriteData( tNode, tFile );\r
+                       break;\r
+               case ACBT_PAUSE:\r
+                       UEF_WritePause( tNode, tFile );\r
+                       break;\r
+               }\r
+               tOldNode = tNode;\r
+               tNode = tNode->next;\r
+        free( tOldNode );\r
+       }\r
+\r
+       fclose( tFile );\r
+}\r
+\r
diff --git a/src/UEF.h b/src/UEF.h
new file mode 100644 (file)
index 0000000..d52b23d
--- /dev/null
+++ b/src/UEF.h
@@ -0,0 +1 @@
+void UEF_Output( struct Acorn_CassetteBlock *list, char *filename );\r
diff --git a/src/UberCassette.h b/src/UberCassette.h
new file mode 100644 (file)
index 0000000..a4f099b
--- /dev/null
@@ -0,0 +1,68 @@
+#include <string.h>\r
+\r
+#ifndef snprintf\r
+#  define snprintf sprintf_s\r
+#endif\r
+#ifdef LINUX\r
+#  define strnicmp strncasecmp\r
+#endif\r
+\r
+#ifndef bool\r
+#  define bool int\r
+#endif\r
+\r
+#ifndef false\r
+#  define false 0\r
+#  define true 1\r
+#endif\r
+\r
+\r
+\r
+typedef unsigned long (*CycleConverter)( double samples );\r
+\r
+enum MachineType { VIC20, C16, C64, BBC, ELECTRON, SPECTRUM, AMSTRAD };\r
+enum VideoType { PAL, NTSC, NTSC2 };\r
+enum AudioChannel { AUDIO_LEFT, AUDIO_RIGHT, AUDIO_BOTH };\r
+enum Loader { LOADER_AUTODETECT, LOADER_ROM, LOADER_SPEEDLOCK, LOADER_UNKNOWN };\r
+\r
+struct MachineData\r
+{\r
+       char string[ 12 ];\r
+       char machineID;\r
+       enum MachineType type;\r
+       unsigned long speed_PAL;\r
+       unsigned long speed_NTSC;\r
+       bool halfWave;\r
+       bool invertWave;\r
+       double divisors[ 2 ];\r
+       CycleConverter converter;\r
+};\r
+\r
+struct Preferences\r
+{\r
+       bool normalise;\r
+       enum AudioChannel audioChannel;\r
+       enum Loader loader;\r
+       int minimumSignalLevel;\r
+};\r
+\r
+extern struct MachineData gMachineData;\r
+extern int gRawLength;\r
+extern double gThresholdDivisor[], gWaveCycles[];\r
+extern int gRawCycles[];\r
+\r
+enum MediumType { WAV, T64, TAP, UEF, TZX, CSW, CDT };\r
+enum AlgorithmType { TRIGGER, WAVE, SAW };\r
+extern enum MediumType gInputType, gOutputType;\r
+extern enum AlgorithmType gAlgorithmType;\r
+extern enum VideoType gVideoType;\r
+extern struct Preferences gPreferences;\r
+\r
+\r
+void AddRawCycle( double length );\r
+void AddMachineCycle( int cycles );\r
+unsigned long CorrectEndianLong( unsigned long source );\r
+unsigned short CorrectEndianShort( unsigned short source );\r
+unsigned long ConvertTo8087Float( double value );\r
+\r
+#define PI 3.1415926535897932f\r
diff --git a/src/UberCassette.sln b/src/UberCassette.sln
new file mode 100644 (file)
index 0000000..828ceca
--- /dev/null
@@ -0,0 +1,20 @@
+\r
+Microsoft Visual Studio Solution File, Format Version 10.00\r
+# Visual Studio 2008\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UberCassette", "UberCassette.vcproj", "{C59EB008-0ED0-4C80-BEE7-4588A21087BF}"\r
+EndProject\r
+Global\r
+       GlobalSection(SolutionConfigurationPlatforms) = preSolution\r
+               Debug|Win32 = Debug|Win32\r
+               Release|Win32 = Release|Win32\r
+       EndGlobalSection\r
+       GlobalSection(ProjectConfigurationPlatforms) = postSolution\r
+               {C59EB008-0ED0-4C80-BEE7-4588A21087BF}.Debug|Win32.ActiveCfg = Debug|Win32\r
+               {C59EB008-0ED0-4C80-BEE7-4588A21087BF}.Debug|Win32.Build.0 = Debug|Win32\r
+               {C59EB008-0ED0-4C80-BEE7-4588A21087BF}.Release|Win32.ActiveCfg = Release|Win32\r
+               {C59EB008-0ED0-4C80-BEE7-4588A21087BF}.Release|Win32.Build.0 = Release|Win32\r
+       EndGlobalSection\r
+       GlobalSection(SolutionProperties) = preSolution\r
+               HideSolutionNode = FALSE\r
+       EndGlobalSection\r
+EndGlobal\r
diff --git a/src/UberCassette.vcproj b/src/UberCassette.vcproj
new file mode 100644 (file)
index 0000000..e58401b
--- /dev/null
@@ -0,0 +1,306 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="9.00"\r
+       Name="UberCassette"\r
+       ProjectGUID="{C59EB008-0ED0-4C80-BEE7-4588A21087BF}"\r
+       RootNamespace="UberCassette"\r
+       Keyword="Win32Proj"\r
+       TargetFrameworkVersion="196613"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="$(SolutionDir)$(ConfigurationName)"\r
+                       IntermediateDirectory="$(ConfigurationName)"\r
+                       ConfigurationType="1"\r
+                       CharacterSet="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               PreprocessorDefinitions="DUMP_RAW;WIN32;_DEBUG;_CONSOLE;_POSIX_;_CRT_SECURE_NO_WARNINGS"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="3"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               DebugInformationFormat="4"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               LinkIncremental="2"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="1"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="$(SolutionDir)$(ConfigurationName)"\r
+                       IntermediateDirectory="$(ConfigurationName)"\r
+                       ConfigurationType="1"\r
+                       CharacterSet="1"\r
+                       WholeProgramOptimization="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="2"\r
+                               EnableIntrinsicFunctions="true"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_POSIX_;_CRT_SECURE_NO_WARNINGS"\r
+                               RuntimeLibrary="2"\r
+                               EnableFunctionLevelLinking="true"\r
+                               UsePrecompiledHeader="0"\r
+                               BrowseInformation="1"\r
+                               WarningLevel="3"\r
+                               DebugInformationFormat="3"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               LinkIncremental="1"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="1"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
+                       >\r
+                       <File\r
+                               RelativePath="main.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Sample.c"\r
+                               >\r
+                       </File>\r
+                       <Filter\r
+                               Name="Machines"\r
+                               >\r
+                               <File\r
+                                       RelativePath=".\Acorn.c"\r
+                                       >\r
+                               </File>\r
+                               <File\r
+                                       RelativePath=".\Amstrad.c"\r
+                                       >\r
+                               </File>\r
+                               <File\r
+                                       RelativePath="CBM.c"\r
+                                       >\r
+                               </File>\r
+                               <File\r
+                                       RelativePath=".\Spectrum.c"\r
+                                       >\r
+                               </File>\r
+                       </Filter>\r
+                       <Filter\r
+                               Name="FileFormats"\r
+                               >\r
+                               <File\r
+                                       RelativePath=".\CSW.c"\r
+                                       >\r
+                               </File>\r
+                               <File\r
+                                       RelativePath="T64.c"\r
+                                       >\r
+                               </File>\r
+                               <File\r
+                                       RelativePath="TAP.c"\r
+                                       >\r
+                               </File>\r
+                               <File\r
+                                       RelativePath=".\TZX.c"\r
+                                       >\r
+                               </File>\r
+                               <File\r
+                                       RelativePath=".\UEF.c"\r
+                                       >\r
+                               </File>\r
+                               <File\r
+                                       RelativePath="WAV.c"\r
+                                       >\r
+                               </File>\r
+                       </Filter>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+                       >\r
+                       <File\r
+                               RelativePath="Machines.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Sample.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="UberCassette.h"\r
+                               >\r
+                       </File>\r
+                       <Filter\r
+                               Name="Machines"\r
+                               >\r
+                               <File\r
+                                       RelativePath=".\Acorn.h"\r
+                                       >\r
+                               </File>\r
+                               <File\r
+                                       RelativePath=".\Amstrad.h"\r
+                                       >\r
+                               </File>\r
+                               <File\r
+                                       RelativePath="CBM.h"\r
+                                       >\r
+                               </File>\r
+                               <File\r
+                                       RelativePath=".\Spectrum.h"\r
+                                       >\r
+                               </File>\r
+                       </Filter>\r
+                       <Filter\r
+                               Name="FileFormats"\r
+                               >\r
+                               <File\r
+                                       RelativePath=".\CSW.h"\r
+                                       >\r
+                               </File>\r
+                               <File\r
+                                       RelativePath="T64.h"\r
+                                       >\r
+                               </File>\r
+                               <File\r
+                                       RelativePath="TAP.h"\r
+                                       >\r
+                               </File>\r
+                               <File\r
+                                       RelativePath=".\TZX.h"\r
+                                       >\r
+                               </File>\r
+                               <File\r
+                                       RelativePath=".\UEF.h"\r
+                                       >\r
+                               </File>\r
+                               <File\r
+                                       RelativePath="WAV.h"\r
+                                       >\r
+                               </File>\r
+                       </Filter>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Resource Files"\r
+                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"\r
+                       UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"\r
+                       >\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/src/WAV.c b/src/WAV.c
new file mode 100644 (file)
index 0000000..d982304
--- /dev/null
+++ b/src/WAV.c
@@ -0,0 +1,334 @@
+/* Helper functions for using WAV files. */\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <math.h>\r
+\r
+#include "UberCassette.h"\r
+#include "WAV.h"\r
+#include "Sample.h"\r
+\r
+struct WAV_ChunkPrototype;\r
+\r
+\r
+\r
+struct WAV_Format gWAVFormat, gOutputWAVFormat;\r
+struct RAW_Format gRAWFormat;\r
+\r
+void WAV_ParseBlock_FMT( struct WAV_FormatChunk *chunk )\r
+{\r
+       gWAVFormat.numberOfChannels = CorrectEndianShort( chunk->numberOfChannels );\r
+       gWAVFormat.sampleRate = CorrectEndianLong( chunk->sampleRate );\r
+       gWAVFormat.significantBitsPerSample = CorrectEndianShort( chunk->significantBitsPerSample );\r
+       return;\r
+}\r
+\r
+void WAV_ParseBlock_DATA( struct WAV_DataChunk *chunk, bool invert )\r
+{\r
+       int tRawSize, tChannel = 0;\r
+       unsigned long tInputByte;\r
+       signed char *tOutputPtr;\r
+    unsigned long tDataSize;\r
+\r
+       // Convert the data to 8-bit signed, 44KHz.\r
+       tRawSize = CorrectEndianLong( chunk->dataSize );\r
+       if ( gWAVFormat.numberOfChannels == 2 )\r
+               tRawSize /= 2;\r
+       if ( gWAVFormat.significantBitsPerSample != 8 )\r
+               tRawSize /= (gWAVFormat.significantBitsPerSample / 8);\r
+\r
+       gRAWFormat.size = tRawSize;\r
+       tOutputPtr = gRAWFormat.data = (signed char *)malloc( tRawSize );\r
+    if  (tOutputPtr == NULL )\r
+    {\r
+        printf( "Out of memory allocating WAV data.\n" );\r
+        return;\r
+    }\r
+\r
+    tDataSize = CorrectEndianLong( chunk->dataSize );\r
+\r
+       for ( tInputByte = 0 ; tInputByte < tDataSize ; )\r
+       {\r
+               if ( tChannel == 0 )\r
+                       *tOutputPtr = 0;\r
+\r
+               if ( tChannel == 1 && gPreferences.audioChannel == AUDIO_LEFT \r
+                       || tChannel == 0 && gPreferences.audioChannel == AUDIO_RIGHT )\r
+               {\r
+                       // Skip the right channel.\r
+                       tInputByte += gWAVFormat.significantBitsPerSample / 8;\r
+                       tChannel++;\r
+                       if ( tChannel > (gWAVFormat.numberOfChannels-1))\r
+                       {\r
+                               tChannel = 0;\r
+                               tOutputPtr++;\r
+                       }\r
+                       continue;\r
+               }\r
+\r
+               tInputByte += (gWAVFormat.significantBitsPerSample / 8) - 1;\r
+\r
+               if ( gWAVFormat.significantBitsPerSample == 8 )\r
+                       *tOutputPtr += (unsigned char)((128 + (int)(chunk->data[ tInputByte++ ])) * (invert ? -1 : 1 ));\r
+               else\r
+                       *tOutputPtr += (signed char)((double)(chunk->data[ tInputByte++ ] * (invert ? -1 : 1 )));\r
+\r
+               tChannel++;\r
+\r
+               if ( tChannel > (gWAVFormat.numberOfChannels-1))\r
+               {\r
+                       tChannel = 0;\r
+                       tOutputPtr++;\r
+               }\r
+       }\r
+\r
+       if ( gPreferences.normalise )\r
+               WAV_Normalise( gRAWFormat );\r
+\r
+       return;\r
+}\r
+\r
+void WAV_Normalise( struct RAW_Format format )\r
+{\r
+       signed char *tPointer = format.data;\r
+       double tAmplify = 0.0f;\r
+       double tTestAmp = 0.0f;\r
+\r
+       while ( tPointer < format.data + format.size )\r
+       {\r
+               if ( *tPointer == -128 || *tPointer == 127 )\r
+               {\r
+                       // No amplification necessary, ta.\r
+                       return;\r
+               }\r
+\r
+               tTestAmp = (double)(abs( *tPointer )) / 127.0f;\r
+               if ( tTestAmp > tAmplify )\r
+                       tAmplify = tTestAmp;\r
+\r
+               tPointer++;\r
+       }\r
+\r
+       if ( tAmplify < 0.00001f )\r
+               return;\r
+\r
+       tPointer = format.data;\r
+       while ( tPointer < format.data + format.size )\r
+       {\r
+               *tPointer++ = (signed char)((double)(*tPointer) / tAmplify);\r
+       }\r
+}\r
+\r
+unsigned long WAV_ParseBlock( struct WAV_ChunkPrototype *chunk, bool invert )\r
+{\r
+       if (!strnicmp( ((struct WAV_ChunkPrototype *)chunk)->ID, "fmt ", 4))\r
+       {\r
+               WAV_ParseBlock_FMT( (struct WAV_FormatChunk *)chunk );\r
+       }\r
+       if ( !strnicmp( ((struct WAV_ChunkPrototype *)chunk)->ID, "data", 4 ))\r
+       {\r
+               WAV_ParseBlock_DATA( (struct WAV_DataChunk *)chunk, invert );\r
+       }\r
+\r
+       return CorrectEndianLong( chunk->dataSize ) + 8;\r
+}\r
+\r
+struct RAW_Format WAV_GetRAW( unsigned char *wavData, bool invert )\r
+{\r
+       struct WAV_Header *tHeader = (struct WAV_Header *)wavData;\r
+       int tFileSize = 0;\r
+       struct WAV_ChunkPrototype *tChunk = NULL;\r
+       unsigned char *tAddress;\r
+       unsigned long tChunkLength;\r
+\r
+    printf( "WAV_GetRaw.\n" );\r
+\r
+       gRAWFormat.data = NULL;\r
+       gRAWFormat.size = 0;\r
+\r
+       if ( strnicmp( (char *)tHeader->ID, "RIFF", 4 ) )\r
+       {\r
+               // Not a valid RIFF file.\r
+               printf("WAV is not a valid RIFF file.\n" );\r
+               return gRAWFormat;\r
+       }\r
+\r
+       if ( strnicmp( (char *)tHeader->RIFFtype, "WAVE", 4 ) )\r
+       {\r
+               // Not a valid WAVE file.\r
+               printf("WAV is not a valid WAVE file.\n" );\r
+               return gRAWFormat;\r
+       }\r
+\r
+       // We have a valid file!\r
+       tFileSize = CorrectEndianLong( tHeader->dataSize ) - 8;\r
+\r
+       // Loop through the chunks till we get useful data.\r
+       tChunk = (struct WAV_ChunkPrototype *)((char *)tHeader + sizeof( struct WAV_Header ));\r
+       tAddress = (unsigned char *)tChunk;\r
+       printf( "tFileSize is %d.\n", tFileSize );\r
+\r
+       while ( ((unsigned char *)tChunk - wavData) < tFileSize )\r
+       {\r
+               // Add on the length of the chunk.\r
+               tChunkLength = WAV_ParseBlock( tChunk, invert );\r
+               tAddress += tChunkLength;\r
+               tChunk = (struct WAV_ChunkPrototype *)tAddress;\r
+       }\r
+\r
+    if ( gRAWFormat.data == NULL )\r
+        return gRAWFormat;\r
+\r
+#if defined(DUMP_RAW)\r
+       {\r
+               FILE *tFile;\r
+        printf( "Dumping RAW file of size %ld bytes.\n", gRAWFormat.size );\r
+#if defined(WIN32)\r
+               tFile = fopen( "c:\\temp\\temp.raw", "wb" );\r
+#else\r
+               tFile = fopen( "temp.raw", "wb" );\r
+#endif\r
+               if ( tFile )\r
+               {\r
+                       fwrite( gRAWFormat.data, gRAWFormat.size, 1, tFile );\r
+                       fclose( tFile );\r
+               }\r
+        printf( "Done.\n" );\r
+       }\r
+#endif\r
+\r
+       return gRAWFormat;\r
+}\r
+\r
+void WAV_Output( char *filename, int *data, unsigned long size, bool invert )\r
+{\r
+       signed char *tWAVSignal = NULL;\r
+\r
+       tWAVSignal = (signed char *)malloc(32 * 1024 * 1024 );\r
+       if ( tWAVSignal == NULL )\r
+       {\r
+               printf( "Can't allocate memory for output WAV file.\n" );\r
+               return;\r
+       }\r
+\r
+       gOutputWAVFormat.numberOfChannels = 1;\r
+       gOutputWAVFormat.sampleRate = 44100;\r
+       gOutputWAVFormat.significantBitsPerSample = 8;\r
+\r
+       // We have a memory space for our WAV now.\r
+       WAV_CreateWAV( filename, tWAVSignal, data, size, invert );\r
+\r
+       free( tWAVSignal );\r
+\r
+       return;\r
+}\r
+\r
+void WAV_CreateWAV( char *filename, signed char *wavBuffer, int *data, int size, bool invert )\r
+{\r
+       struct WAV_Header tHeader;\r
+       struct WAV_FormatChunk tFormatChunk;\r
+       struct WAV_DataChunk tDataChunk;\r
+       int tLength = 0;\r
+       FILE *tOutputFile = NULL;\r
+\r
+       tOutputFile = fopen( filename, "wb" );\r
+       if ( tOutputFile == NULL )\r
+       {\r
+               printf( "Couldn't open output file.\n" );\r
+               return;\r
+       }\r
+       WAV_CreateHeader( &tHeader );\r
+       WAV_CreateFormatChunk( &tFormatChunk );\r
+       WAV_CreateDataChunk( &tDataChunk );\r
+\r
+       tLength = WAV_CreateData( wavBuffer, data, size, invert );\r
+\r
+       tHeader.dataSize = CorrectEndianLong( 24 + 8 + tLength );\r
+       tDataChunk.dataSize = CorrectEndianLong( tLength );\r
+\r
+       fwrite( &tHeader, sizeof( struct WAV_Header ), 1, tOutputFile );\r
+       fwrite( &tFormatChunk, sizeof( struct WAV_FormatChunk ), 1, tOutputFile );\r
+       fwrite( &tDataChunk, sizeof( struct WAV_DataChunk ), 1, tOutputFile );\r
+       fwrite( wavBuffer, tLength, 1, tOutputFile );\r
+\r
+       fclose( tOutputFile );\r
+}\r
+\r
+void WAV_CreateHeader( struct WAV_Header *header )\r
+{\r
+       header->ID[ 0 ] = 'R'; header->ID[ 1 ] = 'I'; header->ID[ 2 ] = 'F'; header->ID[ 3 ] = 'F';\r
+       header->RIFFtype[ 0 ] = 'W'; header->RIFFtype[ 1 ] = 'A'; header->RIFFtype[ 2 ] = 'V'; header->RIFFtype[ 3 ] = 'E';\r
+}\r
+\r
+void WAV_CreateFormatChunk( struct WAV_FormatChunk *formatChunk )\r
+{\r
+       formatChunk->ID[ 0 ] = 'f'; formatChunk->ID[ 1 ] = 'm'; formatChunk->ID[ 2 ] = 't'; formatChunk->ID[ 3 ] = ' ';\r
+       formatChunk->dataSize = CorrectEndianLong( 16 );\r
+       formatChunk->compressionCode = CorrectEndianShort( 1 );\r
+       formatChunk->numberOfChannels = CorrectEndianShort( gOutputWAVFormat.numberOfChannels );\r
+       formatChunk->sampleRate = CorrectEndianLong( gOutputWAVFormat.sampleRate );\r
+       formatChunk->bytesPerSecond = CorrectEndianLong( gOutputWAVFormat.sampleRate * gOutputWAVFormat.numberOfChannels * (gOutputWAVFormat.significantBitsPerSample / 8) );\r
+       formatChunk->blockAlign = CorrectEndianShort( gOutputWAVFormat.numberOfChannels * ( gOutputWAVFormat.significantBitsPerSample / 8 ) );\r
+       formatChunk->significantBitsPerSample = CorrectEndianShort( gOutputWAVFormat.significantBitsPerSample );\r
+}\r
+\r
+void WAV_CreateDataChunk( struct WAV_DataChunk *dataChunk )\r
+{\r
+       sprintf( dataChunk->ID, "data" );\r
+}\r
+\r
+int WAV_CreateData( signed char *wavBuffer, int *data, int size, bool invert )\r
+{\r
+       int tIndex = 0;\r
+       double tYFactor = 0.0f;\r
+       double tCycleLength = 0.0f;\r
+       double tWaveIndex = 0;\r
+       signed char *tWAVPointer = wavBuffer;\r
+       double tXMod = 0.0f;\r
+       double tXPos = 0.0f;\r
+       bool tPhase = false;\r
+\r
+//     for ( tIndex = 0 ; tIndex < (int)gOutputWAVFormat.sampleRate * gOutputWAVFormat.numberOfChannels * gOutputWAVFormat.significantBitsPerSample ; tIndex++ )\r
+//             *tWAVPointer++ = (gOutputWAVFormat.significantBitsPerSample == 8 ? 0x80 : 0x00 );\r
+\r
+       tIndex = 0;\r
+\r
+       while ( tIndex < size )\r
+       {\r
+               if ( data[ tIndex ] > 20000 )\r
+               {\r
+                       // This is likely to be blank space.\r
+                       tYFactor = 0.0f;\r
+               }\r
+               else\r
+               {\r
+                       // We're in a signal.\r
+                       tYFactor = 0.8f;        // Not a full wave, but nice and large.\r
+                       if ( tPhase )\r
+                               tYFactor = -tYFactor;\r
+               }\r
+\r
+               tCycleLength = ConvertFromCycles( data[ tIndex ] );\r
+               tXMod = ((gMachineData.halfWave ? 1 : 2) * PI) / tCycleLength;\r
+\r
+               while ( tWaveIndex < tCycleLength )\r
+               {\r
+                       tXPos = tXMod * tWaveIndex;\r
+                       *tWAVPointer = ((signed char )((tYFactor * sin( tXPos ) * 127.0f)) + 0x80);\r
+                       tWaveIndex += 1.0f;\r
+                       tWAVPointer++;\r
+               }\r
+\r
+               if ( gMachineData.halfWave )\r
+                       tPhase = !tPhase;\r
+               tWaveIndex -= tCycleLength;\r
+               tIndex++;\r
+       }\r
+       \r
+       for ( tIndex = 0 ; tIndex < (int)gOutputWAVFormat.sampleRate * gOutputWAVFormat.numberOfChannels * gOutputWAVFormat.significantBitsPerSample ; tIndex++ )\r
+               *tWAVPointer++ = (gOutputWAVFormat.significantBitsPerSample == 8 ? 0x80 : 0x00 );\r
+\r
+       return (tWAVPointer - wavBuffer);\r
+}\r
+\r
diff --git a/src/WAV.h b/src/WAV.h
new file mode 100644 (file)
index 0000000..7b8757f
--- /dev/null
+++ b/src/WAV.h
@@ -0,0 +1,62 @@
+/* Helper functions for using WAV files. */\r
+\r
+#ifndef __WAV_H__\r
+#define __WAV_H__\r
+\r
+struct WAV_Format\r
+{\r
+       unsigned short numberOfChannels;\r
+       unsigned long sampleRate;\r
+       unsigned short significantBitsPerSample;\r
+};\r
+\r
+struct RAW_Format\r
+{\r
+       unsigned long size;\r
+       signed char *data;\r
+};\r
+\r
+struct WAV_ChunkPrototype\r
+{\r
+       char ID[ 4 ];\r
+       unsigned long dataSize;\r
+};\r
+\r
+struct WAV_Header\r
+{\r
+       char ID[ 4 ];\r
+       unsigned long dataSize;\r
+       char RIFFtype[ 4 ];\r
+};\r
+\r
+struct WAV_FormatChunk\r
+{\r
+       char ID[ 4 ];\r
+       unsigned long dataSize;\r
+       unsigned short compressionCode;\r
+       unsigned short numberOfChannels;\r
+       unsigned long sampleRate;\r
+       unsigned long bytesPerSecond;\r
+       unsigned short blockAlign;\r
+       unsigned short significantBitsPerSample;\r
+};\r
+\r
+struct WAV_DataChunk\r
+{\r
+       char ID[ 4 ];\r
+       unsigned long dataSize;\r
+       signed char data[0];\r
+};\r
+\r
+extern struct WAV_Format gWAVFormat, gOutputWAVFormat;\r
+extern struct RAW_Format gRAWFormat;\r
+struct RAW_Format WAV_GetRAW( unsigned char *wavData, bool invert );\r
+void WAV_CreateWAV( char *filename, signed char *wavBuffer, int *data, int size, bool invert );\r
+void WAV_Output( char *filename, int *data, unsigned long size, bool invert );\r
+void WAV_CreateHeader( struct WAV_Header *header );\r
+void WAV_CreateFormatChunk( struct WAV_FormatChunk *formatChunk );\r
+void WAV_CreateDataChunk( struct WAV_DataChunk *dataChunk );\r
+int WAV_CreateData( signed char *wavBuffer, int *data, int size, bool invert );\r
+void WAV_Normalise( struct RAW_Format format );\r
+\r
+#endif\r
diff --git a/src/linkermap b/src/linkermap
new file mode 100644 (file)
index 0000000..f05c08c
--- /dev/null
@@ -0,0 +1,816 @@
+Archive member included to satisfy reference by file (symbol)
+
+/usr/lib/libc_nonshared.a(elf-init.oS)
+                              /usr/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../lib/crt1.o (__libc_csu_init)
+/usr/lib/libc_nonshared.a(stat.oS)
+                              main.o (stat)
+
+Allokerer fælles symboler
+Fælles symbol       størrelse         fil
+
+gThresholdDivisor   0x10              main.o
+gVideoType          0x4               main.o
+gMachineData        0x48              main.o
+gRAWFormat          0x10              WAV.o
+gWaveLengthTable    0x14000           main.o
+gWaveCycles         0x2000000         main.o
+gPreferences        0x10              main.o
+gAlgorithmType      0x4               main.o
+gThresholds         0xc               main.o
+gRawCycles          0x1000000         main.o
+gSample_ValueTable  0x14000           main.o
+gOutputWAVFormat    0x18              WAV.o
+gInputFilename      0x400             main.o
+gOutputFilename     0x400             main.o
+gWAVFormat          0x18              WAV.o
+
+Discarded input sections
+
+ .note.GNU-stack
+                0x0000000000000000        0x0 /usr/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../lib/crt1.o
+ .note.GNU-stack
+                0x0000000000000000        0x0 /usr/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../lib/crti.o
+ .note.GNU-stack
+                0x0000000000000000        0x0 /usr/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/crtbegin.o
+ .note.GNU-stack
+                0x0000000000000000        0x0 Amstrad.o
+ .note.GNU-stack
+                0x0000000000000000        0x0 Acorn.o
+ .note.GNU-stack
+                0x0000000000000000        0x0 CBM.o
+ .note.GNU-stack
+                0x0000000000000000        0x0 main.o
+ .note.GNU-stack
+                0x0000000000000000        0x0 Sample.o
+ .note.GNU-stack
+                0x0000000000000000        0x0 T64.o
+ .note.GNU-stack
+                0x0000000000000000        0x0 TAP.o
+ .note.GNU-stack
+                0x0000000000000000        0x0 UEF.o
+ .note.GNU-stack
+                0x0000000000000000        0x0 WAV.o
+ .note.GNU-stack
+                0x0000000000000000        0x0 CSW.o
+ .note.GNU-stack
+                0x0000000000000000        0x0 TZX.o
+ .note.GNU-stack
+                0x0000000000000000        0x0 Spectrum.o
+ .note.GNU-stack
+                0x0000000000000000        0x0 /usr/lib/libc_nonshared.a(elf-init.oS)
+ .note.GNU-stack
+                0x0000000000000000        0x0 /usr/lib/libc_nonshared.a(stat.oS)
+ .note.GNU-stack
+                0x0000000000000000        0x0 /usr/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/crtend.o
+ .note.GNU-stack
+                0x0000000000000000        0x0 /usr/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../lib/crtn.o
+
+Hukommelseskonfiguration
+
+Navn             Begyndelse         Længde            Attributter
+*default*        0x0000000000000000 0xffffffffffffffff
+
+Lænkerskript og hukommelsestabel
+
+LOAD /usr/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../lib/crt1.o
+LOAD /usr/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../lib/crti.o
+LOAD /usr/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/crtbegin.o
+LOAD Amstrad.o
+LOAD Acorn.o
+LOAD CBM.o
+LOAD main.o
+LOAD Sample.o
+LOAD T64.o
+LOAD TAP.o
+LOAD UEF.o
+LOAD WAV.o
+LOAD CSW.o
+LOAD TZX.o
+LOAD Spectrum.o
+LOAD /usr/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../lib/libm.so
+START GROUP
+LOAD /usr/lib/libm.so.6
+LOAD /usr/lib/libmvec.so.1
+END GROUP
+LOAD /usr/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/libgcc.a
+LOAD /usr/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../lib/libgcc_s.so
+LOAD /usr/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../lib/libc.so
+START GROUP
+LOAD /usr/lib/libc.so.6
+LOAD /usr/lib/libc_nonshared.a
+LOAD /usr/lib/ld-linux-x86-64.so.2
+END GROUP
+LOAD /usr/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/libgcc.a
+LOAD /usr/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../lib/libgcc_s.so
+LOAD /usr/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/crtend.o
+LOAD /usr/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../lib/crtn.o
+                [!provide]                        PROVIDE (__executable_start, 0x400000)
+                0x0000000000400200                . = (0x400000 + SIZEOF_HEADERS)
+
+.interp         0x0000000000400200       0x1c
+ *(.interp)
+ .interp        0x0000000000400200       0x1c /usr/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../lib/crt1.o
+
+.note.ABI-tag   0x000000000040021c       0x20
+ .note.ABI-tag  0x000000000040021c       0x20 /usr/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../lib/crt1.o
+
+.note.gnu.build-id
+                0x000000000040023c       0x24
+ *(.note.gnu.build-id)
+ .note.gnu.build-id
+                0x000000000040023c       0x24 /usr/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../lib/crt1.o
+
+.hash
+ *(.hash)
+
+.gnu.hash       0x0000000000400260       0x1c
+ *(.gnu.hash)
+ .gnu.hash      0x0000000000400260       0x1c /usr/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../lib/crt1.o
+
+.dynsym         0x0000000000400280      0x288
+ *(.dynsym)
+ .dynsym        0x0000000000400280      0x288 /usr/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../lib/crt1.o
+
+.dynstr         0x0000000000400508      0x11c
+ *(.dynstr)
+ .dynstr        0x0000000000400508      0x11c /usr/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../lib/crt1.o
+
+.gnu.version    0x0000000000400624       0x36
+ *(.gnu.version)
+ .gnu.version   0x0000000000400624       0x36 /usr/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../lib/crt1.o
+
+.gnu.version_d  0x0000000000400660        0x0
+ *(.gnu.version_d)
+ .gnu.version_d
+                0x0000000000400660        0x0 /usr/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../lib/crt1.o
+
+.gnu.version_r  0x0000000000400660       0x50
+ *(.gnu.version_r)
+ .gnu.version_r
+                0x0000000000400660       0x50 /usr/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../lib/crt1.o
+
+.rela.dyn       0x00000000004006b0       0x18
+ *(.rela.init)
+ *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
+ .rela.text     0x00000000004006b0        0x0 /usr/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../lib/crt1.o
+ *(.rela.fini)
+ *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
+ .rela.rodata   0x00000000004006b0        0x0 /usr/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../lib/crt1.o
+ *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
+ *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
+ *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
+ *(.rela.ctors)
+ *(.rela.dtors)
+ *(.rela.got)
+ .rela.got      0x00000000004006b0       0x18 /usr/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../lib/crt1.o
+ *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
+ .rela.bss      0x00000000004006c8        0x0 /usr/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../lib/crt1.o
+ *(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*)
+ *(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*)
+ *(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*)
+ *(.rela.ifunc)
+
+.rela.plt       0x00000000004006c8      0x228
+ *(.rela.plt)
+ .rela.plt      0x00000000004006c8      0x228 /usr/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../lib/crt1.o
+                [!provide]                        PROVIDE (__rela_iplt_start, .)
+ *(.rela.iplt)
+ .rela.iplt     0x00000000004008f0        0x0 /usr/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../lib/crt1.o
+                [!provide]                        PROVIDE (__rela_iplt_end, .)
+
+.init           0x00000000004008f0       0x1a
+ *(SORT(.init))
+ .init          0x00000000004008f0       0x15 /usr/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../lib/crti.o
+                0x00000000004008f0                _init
+ .init          0x0000000000400905        0x5 /usr/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../lib/crtn.o
+
+.plt            0x0000000000400910      0x180
+ *(.plt)
+ .plt           0x0000000000400910      0x180 /usr/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../lib/crt1.o
+                0x0000000000400920                free@@GLIBC_2.2.5
+                0x0000000000400930                putchar@@GLIBC_2.2.5
+                0x0000000000400940                strcpy@@GLIBC_2.2.5
+                0x0000000000400950                puts@@GLIBC_2.2.5
+                0x0000000000400960                fread@@GLIBC_2.2.5
+                0x0000000000400970                atof@@GLIBC_2.2.5
+                0x0000000000400980                fclose@@GLIBC_2.2.5
+                0x0000000000400990                printf@@GLIBC_2.2.5
+                0x00000000004009a0                strrchr@@GLIBC_2.2.5
+                0x00000000004009b0                memset@@GLIBC_2.2.5
+                0x00000000004009c0                __libc_start_main@@GLIBC_2.2.5
+                0x00000000004009d0                frexp@@GLIBC_2.2.5
+                0x00000000004009f0                memcpy@@GLIBC_2.14
+                0x0000000000400a00                __xstat@@GLIBC_2.2.5
+                0x0000000000400a10                malloc@@GLIBC_2.2.5
+                0x0000000000400a20                strncasecmp@@GLIBC_2.2.5
+                0x0000000000400a30                fopen@@GLIBC_2.2.5
+                0x0000000000400a40                sin@@GLIBC_2.2.5
+                0x0000000000400a50                atoi@@GLIBC_2.2.5
+                0x0000000000400a60                sprintf@@GLIBC_2.2.5
+                0x0000000000400a70                exit@@GLIBC_2.2.5
+                0x0000000000400a80                fwrite@@GLIBC_2.2.5
+ *(.iplt)
+ .iplt          0x0000000000400a90        0x0 /usr/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../lib/crt1.o
+
+.plt.bnd
+ *(.plt.bnd)
+
+.text           0x0000000000400a90     0x8cb0
+ *(.text.unlikely .text.*_unlikely .text.unlikely.*)
+ .text.unlikely
+                0x0000000000400a90        0x0 /usr/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/crtbegin.o
+ .text.unlikely
+                0x0000000000400a90        0x0 /usr/lib/libc_nonshared.a(elf-init.oS)
+ .text.unlikely
+                0x0000000000400a90        0x0 /usr/lib/libc_nonshared.a(stat.oS)
+ *(.text.exit .text.exit.*)
+ *(.text.startup .text.startup.*)
+ *(.text.hot .text.hot.*)
+ *(.text .stub .text.* .gnu.linkonce.t.*)
+ .text          0x0000000000400a90       0x2a /usr/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../lib/crt1.o
+                0x0000000000400a90                _start
+ .text          0x0000000000400aba        0x0 /usr/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../lib/crti.o
+ *fill*         0x0000000000400aba        0x6 
+ .text          0x0000000000400ac0       0xc6 /usr/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/crtbegin.o
+ .text          0x0000000000400b86      0x866 Amstrad.o
+                0x0000000000400b86                Amstrad_ParseWAV
+                0x0000000000400c49                Amstrad_BuildTapeBlocks
+ .text          0x00000000004013ec      0x6b2 Acorn.o
+                0x00000000004013ec                Acorn_ParseWAV
+                0x00000000004014db                Acorn_BuildTapeBlocks
+                0x0000000000401909                Acorn_AddHeaderCycles
+                0x000000000040194a                Acorn_AddDataBlock
+                0x00000000004019ab                Acorn_AddBlock
+                0x0000000000401a66                Acorn_AddPause
+ .text          0x0000000000401a9e      0xbf6 CBM.o
+                0x0000000000401a9e                CBM_ParseWAV
+                0x0000000000401bcf                CBM_BuildTapeBlocks
+                0x0000000000401cf0                CBM_ReadData
+                0x000000000040204e                CBM_ReadHeader
+                0x0000000000402257                CBM_FindTapeBlock
+                0x000000000040242b                CBM_FindHeader
+ .text          0x0000000000402694     0x1361 main.o
+                0x0000000000402694                main
+                0x0000000000402728                ParseParameters
+                0x00000000004032f2                GetMediumType
+                0x000000000040341b                AddRawCycle
+                0x00000000004034d7                AddMachineCycle
+                0x0000000000403526                LoadData
+                0x00000000004036d5                SaveData
+                0x00000000004037a0                ShowHelp
+                0x000000000040383d                IsBigEndian
+                0x0000000000403860                CorrectEndianLong
+                0x00000000004038c0                CorrectEndianShort
+                0x00000000004038f7                ConvertTo8087Float
+ .text          0x00000000004039f5     0x2846 Sample.o
+                0x00000000004039f5                BuildRawWaveList
+                0x0000000000403b4c                FindNextWavelengthStart
+                0x0000000000403c59                AddCurveSample
+                0x0000000000403cb1                GetCurveAverage
+                0x0000000000403d25                GetCurvePeak
+                0x0000000000403d72                GetCurveTrough
+                0x0000000000403dbf                HasStartedCurve
+                0x0000000000403e19                AddWave
+                0x0000000000403f08                TriggerWaveAddition
+                0x000000000040481f                BuildRawWaveList_Cleaned
+                0x0000000000404efb                BuildThresholds
+                0x0000000000405843                BuildWavelengthTable
+                0x0000000000405b18                FindWavelength
+                0x0000000000406036                ConvertToCycles
+                0x000000000040611b                ConvertFromCycles
+                0x00000000004061c8                ConvertFromCyclesToSeconds
+ .text          0x000000000040623b      0x37b T64.o
+                0x000000000040623b                T64_WriteHeader
+                0x00000000004064b2                T64_WriteBlocks
+                0x0000000000406534                T64_Output
+ .text          0x00000000004065b6      0x344 TAP.o
+                0x00000000004065b6                TAP_WriteHeader
+                0x00000000004066ba                TAP_WriteBlocks
+                0x000000000040678f                TAP_Output
+                0x000000000040682f                TAP_Parse
+ .text          0x00000000004068fa      0x2f9 UEF.o
+                0x00000000004068fa                UEF_WriteHeader
+                0x0000000000406959                UEF_WriteDummy
+                0x00000000004069c0                UEF_WritePause
+                0x0000000000406a30                UEF_WriteData
+                0x0000000000406abc                UEF_Output
+ .text          0x0000000000406bf3      0xb33 WAV.o
+                0x0000000000406bf3                WAV_ParseBlock_FMT
+                0x0000000000406c4b                WAV_ParseBlock_DATA
+                0x0000000000406e91                WAV_Normalise
+                0x0000000000406f8f                WAV_ParseBlock
+                0x0000000000407005                WAV_GetRAW
+                0x00000000004071ce                WAV_Output
+                0x000000000040725c                WAV_CreateWAV
+                0x00000000004073ab                WAV_CreateHeader
+                0x00000000004073f5                WAV_CreateFormatChunk
+                0x00000000004074ff                WAV_CreateDataChunk
+                0x0000000000407518                WAV_CreateData
+ .text          0x0000000000407726      0x459 CSW.o
+                0x0000000000407726                CSW_WriteHeader
+                0x00000000004077e6                CSW_WriteBlocks
+                0x00000000004079af                CSW_Output
+                0x0000000000407a3a                CSW_Parse
+ .text          0x0000000000407b7f      0xb48 TZX.o
+                0x0000000000407b7f                TZX_WriteHeader
+                0x0000000000407be9                TZX_AddDataBlock
+                0x0000000000407d2c                TZX_AddPureDataBlock
+                0x0000000000407f22                TZX_AddTurboDataBlock
+                0x00000000004081f2                TZX_AddPauseBlock
+                0x00000000004082cd                TZX_AddPulseBlock
+                0x00000000004083c4                TZX_AddToneBlock
+                0x000000000040848a                TZX_WriteBlocks
+                0x000000000040855b                TZX_Output
+                0x00000000004085fc                TZX_Parse
+ .text          0x00000000004086c7      0xfda Spectrum.o
+                0x00000000004086c7                Spectrum_ParseWAV
+                0x000000000040878a                Spectrum_BuildTapeBlocks
+                0x0000000000409275                Spectrum_ReadData
+                0x000000000040928f                Spectrum_ReadHeader
+                0x0000000000409337                Spectrum_FindTapeBlock
+                0x000000000040935c                Spectrum_FindHeader
+                0x0000000000409381                Spectrum_AddBlock
+                0x00000000004094bd                Spectrum_AddPauseBlock
+                0x0000000000409504                Spectrum_AddStandardDataBlock
+                0x0000000000409577                Spectrum_AddTurboDataBlock
+                0x00000000004095e8                Spectrum_AddPureToneBlock
+                0x0000000000409618                Spectrum_AddPulseBlock
+                0x0000000000409648                Spectrum_AddPureDataBlock
+ *fill*         0x00000000004096a1        0xf 
+ .text          0x00000000004096b0       0x72 /usr/lib/libc_nonshared.a(elf-init.oS)
+                0x00000000004096b0                __libc_csu_init
+                0x0000000000409720                __libc_csu_fini
+ *fill*         0x0000000000409722        0xe 
+ .text          0x0000000000409730       0x10 /usr/lib/libc_nonshared.a(stat.oS)
+                0x0000000000409730                __stat
+                0x0000000000409730                stat
+ .text          0x0000000000409740        0x0 /usr/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/crtend.o
+ .text          0x0000000000409740        0x0 /usr/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../lib/crtn.o
+ *(.gnu.warning)
+
+.fini           0x0000000000409740        0x9
+ *(SORT(.fini))
+ .fini          0x0000000000409740        0x4 /usr/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../lib/crti.o
+                0x0000000000409740                _fini
+ .fini          0x0000000000409744        0x5 /usr/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../lib/crtn.o
+                [!provide]                        PROVIDE (__etext, .)
+                [!provide]                        PROVIDE (_etext, .)
+                [!provide]                        PROVIDE (etext, .)
+
+.rodata         0x0000000000409760     0x101c
+ *(.rodata .rodata.* .gnu.linkonce.r.*)
+ .rodata.cst4   0x0000000000409760        0x4 /usr/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../lib/crt1.o
+                0x0000000000409760                _IO_stdin_used
+ *fill*         0x0000000000409764        0x4 
+ .rodata        0x0000000000409768       0x78 Amstrad.o
+ .rodata        0x00000000004097e0       0xac Acorn.o
+                0x00000000004097f0                cDummyByte
+ *fill*         0x000000000040988c        0x4 
+ .rodata        0x0000000000409890       0x98 CBM.o
+                0x0000000000409894                cMinimumCurveGradient
+ *fill*         0x0000000000409928       0x18 
+ .rodata        0x0000000000409940      0x7d0 main.o
+                0x0000000000409960                MACHINE_VIC
+                0x00000000004099c0                MACHINE_C16
+                0x0000000000409a20                MACHINE_C64
+                0x0000000000409a80                MACHINE_BBC
+                0x0000000000409ae0                MACHINE_ELECTRON
+                0x0000000000409b40                MACHINE_SPECTRUM
+                0x0000000000409ba0                MACHINE_AMSTRAD
+ .rodata        0x000000000040a110      0x240 Sample.o
+ .rodata        0x000000000040a350       0x1e T64.o
+ .rodata        0x000000000040a36e       0x4e TAP.o
+ .rodata        0x000000000040a3bc        0x3 UEF.o
+ *fill*         0x000000000040a3bf        0x1 
+ .rodata        0x000000000040a3c0      0x168 WAV.o
+ .rodata        0x000000000040a528       0x98 CSW.o
+ .rodata        0x000000000040a5c0       0x98 TZX.o
+ *fill*         0x000000000040a658        0x8 
+ .rodata        0x000000000040a660      0x11c Spectrum.o
+
+.rodata1
+ *(.rodata1)
+
+.eh_frame_hdr   0x000000000040a77c      0x314
+ *(.eh_frame_hdr)
+ .eh_frame_hdr  0x000000000040a77c      0x314 /usr/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../lib/crt1.o
+
+.eh_frame       0x000000000040aa90      0xca4
+ *(.eh_frame)
+ .eh_frame      0x000000000040aa90       0x30 /usr/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../lib/crt1.o
+ .eh_frame      0x000000000040aac0       0x40 /usr/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../lib/crt1.o
+ .eh_frame      0x000000000040ab00       0x48 Amstrad.o
+                                         0x60 (størrelse inden forenkling)
+ .eh_frame      0x000000000040ab48       0xc0 Acorn.o
+                                         0xd8 (størrelse inden forenkling)
+ .eh_frame      0x000000000040ac08       0xc8 CBM.o
+                                         0xe0 (størrelse inden forenkling)
+ .eh_frame      0x000000000040acd0      0x188 main.o
+                                        0x1a0 (størrelse inden forenkling)
+ .eh_frame      0x000000000040ae58      0x208 Sample.o
+                                        0x220 (størrelse inden forenkling)
+ .eh_frame      0x000000000040b060       0x60 T64.o
+                                         0x78 (størrelse inden forenkling)
+ .eh_frame      0x000000000040b0c0       0x80 TAP.o
+                                         0x98 (størrelse inden forenkling)
+ .eh_frame      0x000000000040b140       0xa8 UEF.o
+                                         0xc0 (størrelse inden forenkling)
+ .eh_frame      0x000000000040b1e8      0x160 WAV.o
+                                        0x178 (størrelse inden forenkling)
+ .eh_frame      0x000000000040b348       0x88 CSW.o
+                                         0xa0 (størrelse inden forenkling)
+ .eh_frame      0x000000000040b3d0      0x140 TZX.o
+                                        0x158 (størrelse inden forenkling)
+ .eh_frame      0x000000000040b510      0x1a8 Spectrum.o
+                                        0x1c0 (størrelse inden forenkling)
+ .eh_frame      0x000000000040b6b8       0x60 /usr/lib/libc_nonshared.a(elf-init.oS)
+                                         0x78 (størrelse inden forenkling)
+ .eh_frame      0x000000000040b718       0x18 /usr/lib/libc_nonshared.a(stat.oS)
+                                         0x30 (størrelse inden forenkling)
+ .eh_frame      0x000000000040b730        0x4 /usr/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/crtend.o
+
+.gcc_except_table
+ *(.gcc_except_table .gcc_except_table.*)
+
+.exception_ranges
+ *(.exception_ranges .exception_ranges*)
+                0x000000000040b734                . = (ALIGN (0x200000) - ((0x200000 - .) & 0x1fffff))
+                0x000000000060c000                . = DATA_SEGMENT_ALIGN (0x200000, 0x1000)
+
+.eh_frame
+ *(.eh_frame)
+
+.gcc_except_table
+ *(.gcc_except_table .gcc_except_table.*)
+
+.exception_ranges
+ *(.exception_ranges .exception_ranges*)
+
+.tdata
+ *(.tdata .tdata.* .gnu.linkonce.td.*)
+
+.tbss
+ *(.tbss .tbss.* .gnu.linkonce.tb.*)
+ *(.tcommon)
+
+.preinit_array  0x000000000060c000        0x0
+                [!provide]                        PROVIDE (__preinit_array_start, .)
+ *(.preinit_array)
+                [!provide]                        PROVIDE (__preinit_array_end, .)
+
+.init_array     0x000000000060c000        0x8
+                0x000000000060c000                PROVIDE (__init_array_start, .)
+ *(SORT(.init_array.*) SORT(.ctors.*))
+ *(.init_array EXCLUDE_FILE(*crtend?.o *crtend.o *crtbegin?.o *crtbegin.o) .ctors)
+ .init_array    0x000000000060c000        0x8 /usr/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/crtbegin.o
+                0x000000000060c008                PROVIDE (__init_array_end, .)
+
+.fini_array     0x000000000060c008        0x8
+                [!provide]                        PROVIDE (__fini_array_start, .)
+ *(SORT(.fini_array.*) SORT(.dtors.*))
+ *(.fini_array EXCLUDE_FILE(*crtend?.o *crtend.o *crtbegin?.o *crtbegin.o) .dtors)
+ .fini_array    0x000000000060c008        0x8 /usr/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/crtbegin.o
+                [!provide]                        PROVIDE (__fini_array_end, .)
+
+.ctors
+ *crtbegin.o(.ctors)