]> Shamusworld >> Repos - wozmaker/commitdiff
Initial commit.
authorShamus Hammons <jlhamm@acm.org>
Sat, 29 Dec 2018 03:43:07 +0000 (21:43 -0600)
committerShamus Hammons <jlhamm@acm.org>
Sat, 29 Dec 2018 03:43:07 +0000 (21:43 -0600)
34 files changed:
.gitignore [new file with mode: 0644]
Makefile [new file with mode: 0644]
cross-compile [new file with mode: 0755]
res/resources.qrc [new file with mode: 0644]
res/woz-icon.png [new file with mode: 0644]
src/analysisthread.cpp [new file with mode: 0644]
src/analysisthread.h [new file with mode: 0644]
src/app.cpp [new file with mode: 0644]
src/app.h [new file with mode: 0644]
src/diskdrawthread.cpp [new file with mode: 0644]
src/diskdrawthread.h [new file with mode: 0644]
src/diskwidget.cpp [new file with mode: 0644]
src/diskwidget.h [new file with mode: 0644]
src/dsp.cpp [new file with mode: 0644]
src/dsp.h [new file with mode: 0644]
src/fileio.cpp [new file with mode: 0644]
src/fileio.h [new file with mode: 0644]
src/global.cpp [new file with mode: 0644]
src/global.h [new file with mode: 0644]
src/infowidget.cpp [new file with mode: 0644]
src/infowidget.h [new file with mode: 0644]
src/mainwidget.cpp [new file with mode: 0644]
src/mainwidget.h [new file with mode: 0644]
src/mainwin.cpp [new file with mode: 0644]
src/mainwin.h [new file with mode: 0644]
src/navwidget.cpp [new file with mode: 0644]
src/navwidget.h [new file with mode: 0644]
src/nibblewidget.cpp [new file with mode: 0644]
src/nibblewidget.h [new file with mode: 0644]
src/tmpwindow.cpp [new file with mode: 0644]
src/tmpwindow.h [new file with mode: 0644]
src/waveformwidget.cpp [new file with mode: 0644]
src/waveformwidget.h [new file with mode: 0644]
wozmaker.pro [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..cee6672
--- /dev/null
@@ -0,0 +1,7 @@
+pix/
+obj/
+mandelbrot/
+gmon.out
+analysis1.ods
+wozmaker
+res/*.xcf
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..8592007
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,980 @@
+#############################################################################
+# Makefile for building: wozmaker
+# Generated by qmake (3.1) (Qt 5.9.4)
+# Project:  wozmaker.pro
+# Template: app
+# Command: /usr/lib64/qt5/bin/qmake -o Makefile wozmaker.pro
+#############################################################################
+
+MAKEFILE      = Makefile
+
+####### Compiler, tools and options
+
+CC            = gcc
+CXX           = g++
+DEFINES       = -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB
+CFLAGS        = -pipe -g -Wall -W -D_REENTRANT -fPIC $(DEFINES)
+CXXFLAGS      = -pipe -g -Wall -W -D_REENTRANT -fPIC $(DEFINES)
+INCPATH       = -I. -Isrc -isystem /usr/include/qt5 -isystem /usr/include/qt5/QtWidgets -isystem /usr/include/qt5/QtGui -isystem /usr/include/qt5/QtCore -Iobj -isystem /usr/include/libdrm -I/usr/lib64/qt5/mkspecs/linux-g++
+QMAKE         = /usr/lib64/qt5/bin/qmake
+DEL_FILE      = rm -f
+CHK_DIR_EXISTS= test -d
+MKDIR         = mkdir -p
+COPY          = cp -f
+COPY_FILE     = cp -f
+COPY_DIR      = cp -f -R
+INSTALL_FILE  = install -m 644 -p
+INSTALL_PROGRAM = install -m 755 -p
+INSTALL_DIR   = cp -f -R
+QINSTALL      = /usr/lib64/qt5/bin/qmake -install qinstall
+QINSTALL_PROGRAM = /usr/lib64/qt5/bin/qmake -install qinstall -exe
+DEL_FILE      = rm -f
+SYMLINK       = ln -f -s
+DEL_DIR       = rmdir
+MOVE          = mv -f
+TAR           = tar -cf
+COMPRESS      = gzip -9f
+DISTNAME      = wozmaker1.0.0
+DISTDIR = /home/shamus/source/apple2/wozmaker/obj/wozmaker1.0.0
+LINK          = g++
+LFLAGS        = 
+LIBS          = $(SUBLIBS) -lQt5Widgets -lQt5Gui -lQt5Core -lGL -lpthread 
+AR            = ar cqs
+RANLIB        = 
+SED           = sed
+STRIP         = strip
+
+####### Output directory
+
+OBJECTS_DIR   = obj/
+
+####### Files
+
+SOURCES       = src/analysisthread.cpp \
+               src/app.cpp \
+               src/diskdrawthread.cpp \
+               src/diskwidget.cpp \
+               src/dsp.cpp \
+               src/fileio.cpp \
+               src/global.cpp \
+               src/infowidget.cpp \
+               src/mainwidget.cpp \
+               src/mainwin.cpp \
+               src/navwidget.cpp \
+               src/nibblewidget.cpp \
+               src/waveformwidget.cpp obj/qrc_resources.cpp \
+               obj/moc_analysisthread.cpp \
+               obj/moc_diskdrawthread.cpp \
+               obj/moc_diskwidget.cpp \
+               obj/moc_infowidget.cpp \
+               obj/moc_mainwidget.cpp \
+               obj/moc_mainwin.cpp \
+               obj/moc_navwidget.cpp \
+               obj/moc_nibblewidget.cpp \
+               obj/moc_waveformwidget.cpp
+OBJECTS       = obj/analysisthread.o \
+               obj/app.o \
+               obj/diskdrawthread.o \
+               obj/diskwidget.o \
+               obj/dsp.o \
+               obj/fileio.o \
+               obj/global.o \
+               obj/infowidget.o \
+               obj/mainwidget.o \
+               obj/mainwin.o \
+               obj/navwidget.o \
+               obj/nibblewidget.o \
+               obj/waveformwidget.o \
+               obj/qrc_resources.o \
+               obj/moc_analysisthread.o \
+               obj/moc_diskdrawthread.o \
+               obj/moc_diskwidget.o \
+               obj/moc_infowidget.o \
+               obj/moc_mainwidget.o \
+               obj/moc_mainwin.o \
+               obj/moc_navwidget.o \
+               obj/moc_nibblewidget.o \
+               obj/moc_waveformwidget.o
+DIST          = /usr/lib64/qt5/mkspecs/features/spec_pre.prf \
+               /usr/lib64/qt5/mkspecs/common/unix.conf \
+               /usr/lib64/qt5/mkspecs/common/linux.conf \
+               /usr/lib64/qt5/mkspecs/common/sanitize.conf \
+               /usr/lib64/qt5/mkspecs/common/gcc-base.conf \
+               /usr/lib64/qt5/mkspecs/common/gcc-base-unix.conf \
+               /usr/lib64/qt5/mkspecs/common/g++-base.conf \
+               /usr/lib64/qt5/mkspecs/common/g++-unix.conf \
+               /usr/lib64/qt5/mkspecs/qconfig.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_Attica.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KActivities.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KActivitiesStats.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KArchive.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KAuth.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KBookmarks.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KCMUtils.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KCodecs.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KCompletion.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KConfigCore.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KConfigGui.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KConfigWidgets.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KCoreAddons.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KCrash.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KDBusAddons.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KDeclarative.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KDESu.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KDNSSD.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KEmoticons.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KGlobalAccel.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KGuiAddons.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KHolidays.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KHtml.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KI18n.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KIconThemes.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KIdleTime.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KIOCore.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KIOFileWidgets.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KIOGui.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KIOWidgets.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_Kirigami2.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KItemModels.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KItemViews.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KJobWidgets.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KJS.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KJSApi.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KJsEmbed.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KNewStuff.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KNewStuffCore.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KNotifications.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KNotifyConfig.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KNTLM.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KParts.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KPeople.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KPeopleWidgets.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KPlotting.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KPty.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KrossCore.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KrossUi.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KRunner.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KScreen.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KService.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KSyntaxHighlighting.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KTextEditor.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KTextWidgets.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KUnitConversion.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KWallet.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KWaylandClient.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KWaylandServer.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KWidgetsAddons.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KWindowSystem.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KXmlGui.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KXmlRpcClient.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_accessibility_support_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_bootstrap_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_concurrent.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_concurrent_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_core.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_core_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_dbus.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_dbus_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_designer.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_designer_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_designercomponents_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_devicediscovery_support_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_egl_support_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_eventdispatcher_support_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_fb_support_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_fontdatabase_support_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_glx_support_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_gui.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_gui_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_help.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_help_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_input_support_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_linuxaccessibility_support_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_location.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_location_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_multimedia.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_multimedia_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_multimediawidgets.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_multimediawidgets_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_network.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_network_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_opengl.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_opengl_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_openglextensions.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_openglextensions_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_packetprotocol_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_platformcompositor_support_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_positioning.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_positioning_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_printsupport.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_printsupport_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_qml.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_qml_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_qmldebug_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_qmldevtools_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_qmltest.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_qmltest_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_qtmultimediaquicktools_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_quick.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_quick_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_quickcontrols2.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_quickcontrols2_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_quickparticles_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_quicktemplates2_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_quickwidgets.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_quickwidgets_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_script.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_script_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_scripttools.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_scripttools_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_sensors.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_sensors_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_serialport.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_serialport_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_service_support_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_sql.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_sql_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_svg.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_svg_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_testlib.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_testlib_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_theme_support_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_uiplugin.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_uitools.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_uitools_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_waylandclient.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_waylandclient_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_waylandcompositor.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_waylandcompositor_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_webchannel.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_webchannel_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_webengine.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_webengine_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_webenginecore.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_webenginecore_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_webenginecoreheaders_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_webenginewidgets.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_webenginewidgets_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_webkit.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_webkit_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_webkitwidgets.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_webkitwidgets_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_widgets.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_widgets_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_x11extras.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_x11extras_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_xcb_qpa_lib_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_xml.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_xml_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_xmlpatterns.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_xmlpatterns_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_Marble.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_phonon4qt5.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_QuickAddons.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_Solid.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_SonnetCore.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_SonnetUi.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_ThreadWeaver.pri \
+               /usr/lib64/qt5/mkspecs/features/qt_functions.prf \
+               /usr/lib64/qt5/mkspecs/features/qt_config.prf \
+               /usr/lib64/qt5/mkspecs/linux-g++/qmake.conf \
+               /usr/lib64/qt5/mkspecs/features/spec_post.prf \
+               .qmake.stash \
+               /usr/lib64/qt5/mkspecs/features/exclusive_builds.prf \
+               /usr/lib64/qt5/mkspecs/features/toolchain.prf \
+               /usr/lib64/qt5/mkspecs/features/default_pre.prf \
+               /usr/lib64/qt5/mkspecs/features/resolve_config.prf \
+               /usr/lib64/qt5/mkspecs/features/default_post.prf \
+               /usr/lib64/qt5/mkspecs/features/warn_on.prf \
+               /usr/lib64/qt5/mkspecs/features/qt.prf \
+               /usr/lib64/qt5/mkspecs/features/resources.prf \
+               /usr/lib64/qt5/mkspecs/features/moc.prf \
+               /usr/lib64/qt5/mkspecs/features/unix/opengl.prf \
+               /usr/lib64/qt5/mkspecs/features/uic.prf \
+               /usr/lib64/qt5/mkspecs/features/unix/thread.prf \
+               /usr/lib64/qt5/mkspecs/features/qmake_use.prf \
+               /usr/lib64/qt5/mkspecs/features/file_copies.prf \
+               /usr/lib64/qt5/mkspecs/features/testcase_targets.prf \
+               /usr/lib64/qt5/mkspecs/features/exceptions.prf \
+               /usr/lib64/qt5/mkspecs/features/yacc.prf \
+               /usr/lib64/qt5/mkspecs/features/lex.prf \
+               wozmaker.pro src/analysisthread.h \
+               src/app.h \
+               src/diskdrawthread.h \
+               src/diskwidget.h \
+               src/dsp.h \
+               src/fileio.h \
+               src/global.h \
+               src/infowidget.h \
+               src/mainwidget.h \
+               src/mainwin.h \
+               src/navwidget.h \
+               src/nibblewidget.h \
+               src/waveformwidget.h src/analysisthread.cpp \
+               src/app.cpp \
+               src/diskdrawthread.cpp \
+               src/diskwidget.cpp \
+               src/dsp.cpp \
+               src/fileio.cpp \
+               src/global.cpp \
+               src/infowidget.cpp \
+               src/mainwidget.cpp \
+               src/mainwin.cpp \
+               src/navwidget.cpp \
+               src/nibblewidget.cpp \
+               src/waveformwidget.cpp
+QMAKE_TARGET  = wozmaker
+DESTDIR       = 
+TARGET        = wozmaker
+
+
+first: all
+####### Build rules
+
+$(TARGET):  $(OBJECTS)  
+       $(LINK) $(LFLAGS) -o $(TARGET) $(OBJECTS) $(OBJCOMP) $(LIBS)
+
+Makefile: wozmaker.pro /usr/lib64/qt5/mkspecs/linux-g++/qmake.conf /usr/lib64/qt5/mkspecs/features/spec_pre.prf \
+               /usr/lib64/qt5/mkspecs/common/unix.conf \
+               /usr/lib64/qt5/mkspecs/common/linux.conf \
+               /usr/lib64/qt5/mkspecs/common/sanitize.conf \
+               /usr/lib64/qt5/mkspecs/common/gcc-base.conf \
+               /usr/lib64/qt5/mkspecs/common/gcc-base-unix.conf \
+               /usr/lib64/qt5/mkspecs/common/g++-base.conf \
+               /usr/lib64/qt5/mkspecs/common/g++-unix.conf \
+               /usr/lib64/qt5/mkspecs/qconfig.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_Attica.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KActivities.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KActivitiesStats.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KArchive.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KAuth.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KBookmarks.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KCMUtils.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KCodecs.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KCompletion.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KConfigCore.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KConfigGui.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KConfigWidgets.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KCoreAddons.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KCrash.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KDBusAddons.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KDeclarative.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KDESu.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KDNSSD.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KEmoticons.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KGlobalAccel.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KGuiAddons.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KHolidays.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KHtml.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KI18n.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KIconThemes.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KIdleTime.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KIOCore.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KIOFileWidgets.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KIOGui.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KIOWidgets.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_Kirigami2.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KItemModels.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KItemViews.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KJobWidgets.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KJS.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KJSApi.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KJsEmbed.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KNewStuff.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KNewStuffCore.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KNotifications.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KNotifyConfig.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KNTLM.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KParts.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KPeople.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KPeopleWidgets.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KPlotting.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KPty.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KrossCore.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KrossUi.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KRunner.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KScreen.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KService.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KSyntaxHighlighting.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KTextEditor.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KTextWidgets.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KUnitConversion.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KWallet.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KWaylandClient.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KWaylandServer.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KWidgetsAddons.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KWindowSystem.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KXmlGui.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_KXmlRpcClient.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_accessibility_support_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_bootstrap_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_concurrent.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_concurrent_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_core.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_core_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_dbus.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_dbus_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_designer.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_designer_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_designercomponents_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_devicediscovery_support_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_egl_support_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_eventdispatcher_support_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_fb_support_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_fontdatabase_support_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_glx_support_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_gui.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_gui_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_help.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_help_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_input_support_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_linuxaccessibility_support_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_location.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_location_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_multimedia.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_multimedia_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_multimediawidgets.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_multimediawidgets_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_network.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_network_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_opengl.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_opengl_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_openglextensions.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_openglextensions_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_packetprotocol_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_platformcompositor_support_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_positioning.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_positioning_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_printsupport.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_printsupport_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_qml.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_qml_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_qmldebug_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_qmldevtools_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_qmltest.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_qmltest_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_qtmultimediaquicktools_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_quick.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_quick_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_quickcontrols2.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_quickcontrols2_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_quickparticles_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_quicktemplates2_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_quickwidgets.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_quickwidgets_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_script.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_script_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_scripttools.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_scripttools_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_sensors.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_sensors_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_serialport.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_serialport_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_service_support_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_sql.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_sql_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_svg.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_svg_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_testlib.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_testlib_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_theme_support_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_uiplugin.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_uitools.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_uitools_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_waylandclient.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_waylandclient_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_waylandcompositor.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_waylandcompositor_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_webchannel.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_webchannel_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_webengine.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_webengine_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_webenginecore.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_webenginecore_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_webenginecoreheaders_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_webenginewidgets.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_webenginewidgets_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_webkit.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_webkit_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_webkitwidgets.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_webkitwidgets_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_widgets.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_widgets_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_x11extras.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_x11extras_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_xcb_qpa_lib_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_xml.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_xml_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_xmlpatterns.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_lib_xmlpatterns_private.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_Marble.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_phonon4qt5.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_QuickAddons.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_Solid.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_SonnetCore.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_SonnetUi.pri \
+               /usr/lib64/qt5/mkspecs/modules/qt_ThreadWeaver.pri \
+               /usr/lib64/qt5/mkspecs/features/qt_functions.prf \
+               /usr/lib64/qt5/mkspecs/features/qt_config.prf \
+               /usr/lib64/qt5/mkspecs/linux-g++/qmake.conf \
+               /usr/lib64/qt5/mkspecs/features/spec_post.prf \
+               .qmake.stash \
+               /usr/lib64/qt5/mkspecs/features/exclusive_builds.prf \
+               /usr/lib64/qt5/mkspecs/features/toolchain.prf \
+               /usr/lib64/qt5/mkspecs/features/default_pre.prf \
+               /usr/lib64/qt5/mkspecs/features/resolve_config.prf \
+               /usr/lib64/qt5/mkspecs/features/default_post.prf \
+               /usr/lib64/qt5/mkspecs/features/warn_on.prf \
+               /usr/lib64/qt5/mkspecs/features/qt.prf \
+               /usr/lib64/qt5/mkspecs/features/resources.prf \
+               /usr/lib64/qt5/mkspecs/features/moc.prf \
+               /usr/lib64/qt5/mkspecs/features/unix/opengl.prf \
+               /usr/lib64/qt5/mkspecs/features/uic.prf \
+               /usr/lib64/qt5/mkspecs/features/unix/thread.prf \
+               /usr/lib64/qt5/mkspecs/features/qmake_use.prf \
+               /usr/lib64/qt5/mkspecs/features/file_copies.prf \
+               /usr/lib64/qt5/mkspecs/features/testcase_targets.prf \
+               /usr/lib64/qt5/mkspecs/features/exceptions.prf \
+               /usr/lib64/qt5/mkspecs/features/yacc.prf \
+               /usr/lib64/qt5/mkspecs/features/lex.prf \
+               wozmaker.pro \
+               res/resources.qrc \
+               /usr/lib64/libQt5Widgets.prl \
+               /usr/lib64/libQt5Gui.prl \
+               /usr/lib64/libQt5Core.prl
+       $(QMAKE) -o Makefile wozmaker.pro
+/usr/lib64/qt5/mkspecs/features/spec_pre.prf:
+/usr/lib64/qt5/mkspecs/common/unix.conf:
+/usr/lib64/qt5/mkspecs/common/linux.conf:
+/usr/lib64/qt5/mkspecs/common/sanitize.conf:
+/usr/lib64/qt5/mkspecs/common/gcc-base.conf:
+/usr/lib64/qt5/mkspecs/common/gcc-base-unix.conf:
+/usr/lib64/qt5/mkspecs/common/g++-base.conf:
+/usr/lib64/qt5/mkspecs/common/g++-unix.conf:
+/usr/lib64/qt5/mkspecs/qconfig.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_Attica.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KActivities.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KActivitiesStats.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KArchive.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KAuth.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KBookmarks.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KCMUtils.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KCodecs.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KCompletion.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KConfigCore.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KConfigGui.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KConfigWidgets.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KCoreAddons.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KCrash.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KDBusAddons.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KDeclarative.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KDESu.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KDNSSD.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KEmoticons.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KGlobalAccel.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KGuiAddons.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KHolidays.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KHtml.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KI18n.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KIconThemes.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KIdleTime.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KIOCore.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KIOFileWidgets.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KIOGui.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KIOWidgets.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_Kirigami2.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KItemModels.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KItemViews.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KJobWidgets.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KJS.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KJSApi.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KJsEmbed.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KNewStuff.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KNewStuffCore.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KNotifications.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KNotifyConfig.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KNTLM.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KParts.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KPeople.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KPeopleWidgets.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KPlotting.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KPty.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KrossCore.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KrossUi.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KRunner.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KScreen.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KService.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KSyntaxHighlighting.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KTextEditor.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KTextWidgets.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KUnitConversion.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KWallet.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KWaylandClient.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KWaylandServer.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KWidgetsAddons.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KWindowSystem.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KXmlGui.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_KXmlRpcClient.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_accessibility_support_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_bootstrap_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_concurrent.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_concurrent_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_core.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_core_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_dbus.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_dbus_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_designer.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_designer_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_designercomponents_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_devicediscovery_support_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_egl_support_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_eventdispatcher_support_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_fb_support_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_fontdatabase_support_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_glx_support_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_gui.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_gui_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_help.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_help_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_input_support_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_linuxaccessibility_support_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_location.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_location_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_multimedia.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_multimedia_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_multimediawidgets.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_multimediawidgets_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_network.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_network_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_opengl.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_opengl_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_openglextensions.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_openglextensions_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_packetprotocol_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_platformcompositor_support_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_positioning.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_positioning_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_printsupport.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_printsupport_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_qml.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_qml_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_qmldebug_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_qmldevtools_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_qmltest.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_qmltest_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_qtmultimediaquicktools_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_quick.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_quick_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_quickcontrols2.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_quickcontrols2_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_quickparticles_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_quicktemplates2_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_quickwidgets.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_quickwidgets_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_script.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_script_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_scripttools.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_scripttools_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_sensors.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_sensors_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_serialport.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_serialport_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_service_support_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_sql.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_sql_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_svg.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_svg_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_testlib.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_testlib_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_theme_support_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_uiplugin.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_uitools.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_uitools_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_waylandclient.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_waylandclient_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_waylandcompositor.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_waylandcompositor_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_webchannel.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_webchannel_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_webengine.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_webengine_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_webenginecore.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_webenginecore_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_webenginecoreheaders_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_webenginewidgets.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_webenginewidgets_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_webkit.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_webkit_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_webkitwidgets.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_webkitwidgets_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_widgets.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_widgets_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_x11extras.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_x11extras_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_xcb_qpa_lib_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_xml.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_xml_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_xmlpatterns.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_lib_xmlpatterns_private.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_Marble.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_phonon4qt5.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_QuickAddons.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_Solid.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_SonnetCore.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_SonnetUi.pri:
+/usr/lib64/qt5/mkspecs/modules/qt_ThreadWeaver.pri:
+/usr/lib64/qt5/mkspecs/features/qt_functions.prf:
+/usr/lib64/qt5/mkspecs/features/qt_config.prf:
+/usr/lib64/qt5/mkspecs/linux-g++/qmake.conf:
+/usr/lib64/qt5/mkspecs/features/spec_post.prf:
+.qmake.stash:
+/usr/lib64/qt5/mkspecs/features/exclusive_builds.prf:
+/usr/lib64/qt5/mkspecs/features/toolchain.prf:
+/usr/lib64/qt5/mkspecs/features/default_pre.prf:
+/usr/lib64/qt5/mkspecs/features/resolve_config.prf:
+/usr/lib64/qt5/mkspecs/features/default_post.prf:
+/usr/lib64/qt5/mkspecs/features/warn_on.prf:
+/usr/lib64/qt5/mkspecs/features/qt.prf:
+/usr/lib64/qt5/mkspecs/features/resources.prf:
+/usr/lib64/qt5/mkspecs/features/moc.prf:
+/usr/lib64/qt5/mkspecs/features/unix/opengl.prf:
+/usr/lib64/qt5/mkspecs/features/uic.prf:
+/usr/lib64/qt5/mkspecs/features/unix/thread.prf:
+/usr/lib64/qt5/mkspecs/features/qmake_use.prf:
+/usr/lib64/qt5/mkspecs/features/file_copies.prf:
+/usr/lib64/qt5/mkspecs/features/testcase_targets.prf:
+/usr/lib64/qt5/mkspecs/features/exceptions.prf:
+/usr/lib64/qt5/mkspecs/features/yacc.prf:
+/usr/lib64/qt5/mkspecs/features/lex.prf:
+wozmaker.pro:
+res/resources.qrc:
+/usr/lib64/libQt5Widgets.prl:
+/usr/lib64/libQt5Gui.prl:
+/usr/lib64/libQt5Core.prl:
+qmake: FORCE
+       @$(QMAKE) -o Makefile wozmaker.pro
+
+qmake_all: FORCE
+
+
+all: Makefile $(TARGET)
+
+dist: distdir FORCE
+       (cd `dirname $(DISTDIR)` && $(TAR) $(DISTNAME).tar $(DISTNAME) && $(COMPRESS) $(DISTNAME).tar) && $(MOVE) `dirname $(DISTDIR)`/$(DISTNAME).tar.gz . && $(DEL_FILE) -r $(DISTDIR)
+
+distdir: FORCE
+       @test -d $(DISTDIR) || mkdir -p $(DISTDIR)
+       $(COPY_FILE) --parents $(DIST) $(DISTDIR)/
+       $(COPY_FILE) --parents res/resources.qrc $(DISTDIR)/
+       $(COPY_FILE) --parents /usr/lib64/qt5/mkspecs/features/data/dummy.cpp $(DISTDIR)/
+       $(COPY_FILE) --parents src/analysisthread.h src/app.h src/diskdrawthread.h src/diskwidget.h src/dsp.h src/fileio.h src/global.h src/infowidget.h src/mainwidget.h src/mainwin.h src/navwidget.h src/nibblewidget.h src/waveformwidget.h $(DISTDIR)/
+       $(COPY_FILE) --parents src/analysisthread.cpp src/app.cpp src/diskdrawthread.cpp src/diskwidget.cpp src/dsp.cpp src/fileio.cpp src/global.cpp src/infowidget.cpp src/mainwidget.cpp src/mainwin.cpp src/navwidget.cpp src/nibblewidget.cpp src/waveformwidget.cpp $(DISTDIR)/
+
+
+clean: compiler_clean 
+       -$(DEL_FILE) $(OBJECTS)
+       -$(DEL_FILE) *~ core *.core
+
+
+distclean: clean 
+       -$(DEL_FILE) $(TARGET) 
+       -$(DEL_FILE) .qmake.stash
+       -$(DEL_FILE) Makefile
+
+
+####### Sub-libraries
+
+mocclean: compiler_moc_header_clean compiler_moc_source_clean
+
+mocables: compiler_moc_header_make_all compiler_moc_source_make_all
+
+check: first
+
+benchmark: first
+
+compiler_rcc_make_all: obj/qrc_resources.cpp
+compiler_rcc_clean:
+       -$(DEL_FILE) obj/qrc_resources.cpp
+obj/qrc_resources.cpp: res/resources.qrc \
+               /usr/lib64/qt5/bin/rcc \
+               res/woz-icon.png
+       /usr/lib64/qt5/bin/rcc -name resources res/resources.qrc -o obj/qrc_resources.cpp
+
+compiler_moc_predefs_make_all: obj/moc_predefs.h
+compiler_moc_predefs_clean:
+       -$(DEL_FILE) obj/moc_predefs.h
+obj/moc_predefs.h: /usr/lib64/qt5/mkspecs/features/data/dummy.cpp
+       g++ -pipe -g -Wall -W -dM -E -o obj/moc_predefs.h /usr/lib64/qt5/mkspecs/features/data/dummy.cpp
+
+compiler_moc_header_make_all: obj/moc_analysisthread.cpp obj/moc_diskdrawthread.cpp obj/moc_diskwidget.cpp obj/moc_infowidget.cpp obj/moc_mainwidget.cpp obj/moc_mainwin.cpp obj/moc_navwidget.cpp obj/moc_nibblewidget.cpp obj/moc_waveformwidget.cpp
+compiler_moc_header_clean:
+       -$(DEL_FILE) obj/moc_analysisthread.cpp obj/moc_diskdrawthread.cpp obj/moc_diskwidget.cpp obj/moc_infowidget.cpp obj/moc_mainwidget.cpp obj/moc_mainwin.cpp obj/moc_navwidget.cpp obj/moc_nibblewidget.cpp obj/moc_waveformwidget.cpp
+obj/moc_analysisthread.cpp: src/analysisthread.h \
+               obj/moc_predefs.h \
+               /usr/lib64/qt5/bin/moc
+       /usr/lib64/qt5/bin/moc $(DEFINES) --include obj/moc_predefs.h -I/usr/lib64/qt5/mkspecs/linux-g++ -I/home/shamus/source/apple2/wozmaker -I/home/shamus/source/apple2/wozmaker/src -I/usr/include/qt5 -I/usr/include/qt5/QtWidgets -I/usr/include/qt5/QtGui -I/usr/include/qt5/QtCore -I/usr/lib/gcc/x86_64-pc-linux-gnu/7.3.1/include/g++-v7.3.1 -I/usr/lib/gcc/x86_64-pc-linux-gnu/7.3.1/include/g++-v7.3.1/x86_64-pc-linux-gnu -I/usr/lib/gcc/x86_64-pc-linux-gnu/7.3.1/include/g++-v7.3.1/backward -I/usr/lib/gcc/x86_64-pc-linux-gnu/7.3.1/include -I/usr/lib/gcc/x86_64-pc-linux-gnu/7.3.1/include-fixed -I/usr/include src/analysisthread.h -o obj/moc_analysisthread.cpp
+
+obj/moc_diskdrawthread.cpp: src/diskdrawthread.h \
+               obj/moc_predefs.h \
+               /usr/lib64/qt5/bin/moc
+       /usr/lib64/qt5/bin/moc $(DEFINES) --include obj/moc_predefs.h -I/usr/lib64/qt5/mkspecs/linux-g++ -I/home/shamus/source/apple2/wozmaker -I/home/shamus/source/apple2/wozmaker/src -I/usr/include/qt5 -I/usr/include/qt5/QtWidgets -I/usr/include/qt5/QtGui -I/usr/include/qt5/QtCore -I/usr/lib/gcc/x86_64-pc-linux-gnu/7.3.1/include/g++-v7.3.1 -I/usr/lib/gcc/x86_64-pc-linux-gnu/7.3.1/include/g++-v7.3.1/x86_64-pc-linux-gnu -I/usr/lib/gcc/x86_64-pc-linux-gnu/7.3.1/include/g++-v7.3.1/backward -I/usr/lib/gcc/x86_64-pc-linux-gnu/7.3.1/include -I/usr/lib/gcc/x86_64-pc-linux-gnu/7.3.1/include-fixed -I/usr/include src/diskdrawthread.h -o obj/moc_diskdrawthread.cpp
+
+obj/moc_diskwidget.cpp: src/diskwidget.h \
+               obj/moc_predefs.h \
+               /usr/lib64/qt5/bin/moc
+       /usr/lib64/qt5/bin/moc $(DEFINES) --include obj/moc_predefs.h -I/usr/lib64/qt5/mkspecs/linux-g++ -I/home/shamus/source/apple2/wozmaker -I/home/shamus/source/apple2/wozmaker/src -I/usr/include/qt5 -I/usr/include/qt5/QtWidgets -I/usr/include/qt5/QtGui -I/usr/include/qt5/QtCore -I/usr/lib/gcc/x86_64-pc-linux-gnu/7.3.1/include/g++-v7.3.1 -I/usr/lib/gcc/x86_64-pc-linux-gnu/7.3.1/include/g++-v7.3.1/x86_64-pc-linux-gnu -I/usr/lib/gcc/x86_64-pc-linux-gnu/7.3.1/include/g++-v7.3.1/backward -I/usr/lib/gcc/x86_64-pc-linux-gnu/7.3.1/include -I/usr/lib/gcc/x86_64-pc-linux-gnu/7.3.1/include-fixed -I/usr/include src/diskwidget.h -o obj/moc_diskwidget.cpp
+
+obj/moc_infowidget.cpp: src/infowidget.h \
+               obj/moc_predefs.h \
+               /usr/lib64/qt5/bin/moc
+       /usr/lib64/qt5/bin/moc $(DEFINES) --include obj/moc_predefs.h -I/usr/lib64/qt5/mkspecs/linux-g++ -I/home/shamus/source/apple2/wozmaker -I/home/shamus/source/apple2/wozmaker/src -I/usr/include/qt5 -I/usr/include/qt5/QtWidgets -I/usr/include/qt5/QtGui -I/usr/include/qt5/QtCore -I/usr/lib/gcc/x86_64-pc-linux-gnu/7.3.1/include/g++-v7.3.1 -I/usr/lib/gcc/x86_64-pc-linux-gnu/7.3.1/include/g++-v7.3.1/x86_64-pc-linux-gnu -I/usr/lib/gcc/x86_64-pc-linux-gnu/7.3.1/include/g++-v7.3.1/backward -I/usr/lib/gcc/x86_64-pc-linux-gnu/7.3.1/include -I/usr/lib/gcc/x86_64-pc-linux-gnu/7.3.1/include-fixed -I/usr/include src/infowidget.h -o obj/moc_infowidget.cpp
+
+obj/moc_mainwidget.cpp: src/mainwidget.h \
+               obj/moc_predefs.h \
+               /usr/lib64/qt5/bin/moc
+       /usr/lib64/qt5/bin/moc $(DEFINES) --include obj/moc_predefs.h -I/usr/lib64/qt5/mkspecs/linux-g++ -I/home/shamus/source/apple2/wozmaker -I/home/shamus/source/apple2/wozmaker/src -I/usr/include/qt5 -I/usr/include/qt5/QtWidgets -I/usr/include/qt5/QtGui -I/usr/include/qt5/QtCore -I/usr/lib/gcc/x86_64-pc-linux-gnu/7.3.1/include/g++-v7.3.1 -I/usr/lib/gcc/x86_64-pc-linux-gnu/7.3.1/include/g++-v7.3.1/x86_64-pc-linux-gnu -I/usr/lib/gcc/x86_64-pc-linux-gnu/7.3.1/include/g++-v7.3.1/backward -I/usr/lib/gcc/x86_64-pc-linux-gnu/7.3.1/include -I/usr/lib/gcc/x86_64-pc-linux-gnu/7.3.1/include-fixed -I/usr/include src/mainwidget.h -o obj/moc_mainwidget.cpp
+
+obj/moc_mainwin.cpp: src/mainwin.h \
+               obj/moc_predefs.h \
+               /usr/lib64/qt5/bin/moc
+       /usr/lib64/qt5/bin/moc $(DEFINES) --include obj/moc_predefs.h -I/usr/lib64/qt5/mkspecs/linux-g++ -I/home/shamus/source/apple2/wozmaker -I/home/shamus/source/apple2/wozmaker/src -I/usr/include/qt5 -I/usr/include/qt5/QtWidgets -I/usr/include/qt5/QtGui -I/usr/include/qt5/QtCore -I/usr/lib/gcc/x86_64-pc-linux-gnu/7.3.1/include/g++-v7.3.1 -I/usr/lib/gcc/x86_64-pc-linux-gnu/7.3.1/include/g++-v7.3.1/x86_64-pc-linux-gnu -I/usr/lib/gcc/x86_64-pc-linux-gnu/7.3.1/include/g++-v7.3.1/backward -I/usr/lib/gcc/x86_64-pc-linux-gnu/7.3.1/include -I/usr/lib/gcc/x86_64-pc-linux-gnu/7.3.1/include-fixed -I/usr/include src/mainwin.h -o obj/moc_mainwin.cpp
+
+obj/moc_navwidget.cpp: src/navwidget.h \
+               obj/moc_predefs.h \
+               /usr/lib64/qt5/bin/moc
+       /usr/lib64/qt5/bin/moc $(DEFINES) --include obj/moc_predefs.h -I/usr/lib64/qt5/mkspecs/linux-g++ -I/home/shamus/source/apple2/wozmaker -I/home/shamus/source/apple2/wozmaker/src -I/usr/include/qt5 -I/usr/include/qt5/QtWidgets -I/usr/include/qt5/QtGui -I/usr/include/qt5/QtCore -I/usr/lib/gcc/x86_64-pc-linux-gnu/7.3.1/include/g++-v7.3.1 -I/usr/lib/gcc/x86_64-pc-linux-gnu/7.3.1/include/g++-v7.3.1/x86_64-pc-linux-gnu -I/usr/lib/gcc/x86_64-pc-linux-gnu/7.3.1/include/g++-v7.3.1/backward -I/usr/lib/gcc/x86_64-pc-linux-gnu/7.3.1/include -I/usr/lib/gcc/x86_64-pc-linux-gnu/7.3.1/include-fixed -I/usr/include src/navwidget.h -o obj/moc_navwidget.cpp
+
+obj/moc_nibblewidget.cpp: src/nibblewidget.h \
+               obj/moc_predefs.h \
+               /usr/lib64/qt5/bin/moc
+       /usr/lib64/qt5/bin/moc $(DEFINES) --include obj/moc_predefs.h -I/usr/lib64/qt5/mkspecs/linux-g++ -I/home/shamus/source/apple2/wozmaker -I/home/shamus/source/apple2/wozmaker/src -I/usr/include/qt5 -I/usr/include/qt5/QtWidgets -I/usr/include/qt5/QtGui -I/usr/include/qt5/QtCore -I/usr/lib/gcc/x86_64-pc-linux-gnu/7.3.1/include/g++-v7.3.1 -I/usr/lib/gcc/x86_64-pc-linux-gnu/7.3.1/include/g++-v7.3.1/x86_64-pc-linux-gnu -I/usr/lib/gcc/x86_64-pc-linux-gnu/7.3.1/include/g++-v7.3.1/backward -I/usr/lib/gcc/x86_64-pc-linux-gnu/7.3.1/include -I/usr/lib/gcc/x86_64-pc-linux-gnu/7.3.1/include-fixed -I/usr/include src/nibblewidget.h -o obj/moc_nibblewidget.cpp
+
+obj/moc_waveformwidget.cpp: src/waveformwidget.h \
+               obj/moc_predefs.h \
+               /usr/lib64/qt5/bin/moc
+       /usr/lib64/qt5/bin/moc $(DEFINES) --include obj/moc_predefs.h -I/usr/lib64/qt5/mkspecs/linux-g++ -I/home/shamus/source/apple2/wozmaker -I/home/shamus/source/apple2/wozmaker/src -I/usr/include/qt5 -I/usr/include/qt5/QtWidgets -I/usr/include/qt5/QtGui -I/usr/include/qt5/QtCore -I/usr/lib/gcc/x86_64-pc-linux-gnu/7.3.1/include/g++-v7.3.1 -I/usr/lib/gcc/x86_64-pc-linux-gnu/7.3.1/include/g++-v7.3.1/x86_64-pc-linux-gnu -I/usr/lib/gcc/x86_64-pc-linux-gnu/7.3.1/include/g++-v7.3.1/backward -I/usr/lib/gcc/x86_64-pc-linux-gnu/7.3.1/include -I/usr/lib/gcc/x86_64-pc-linux-gnu/7.3.1/include-fixed -I/usr/include src/waveformwidget.h -o obj/moc_waveformwidget.cpp
+
+compiler_moc_source_make_all:
+compiler_moc_source_clean:
+compiler_uic_make_all:
+compiler_uic_clean:
+compiler_yacc_decl_make_all:
+compiler_yacc_decl_clean:
+compiler_yacc_impl_make_all:
+compiler_yacc_impl_clean:
+compiler_lex_make_all:
+compiler_lex_clean:
+compiler_clean: compiler_rcc_clean compiler_moc_predefs_clean compiler_moc_header_clean 
+
+####### Compile
+
+obj/analysisthread.o: src/analysisthread.cpp src/analysisthread.h \
+               src/dsp.h \
+               src/fileio.h \
+               src/global.h
+       $(CXX) -c $(CXXFLAGS) $(INCPATH) -o obj/analysisthread.o src/analysisthread.cpp
+
+obj/app.o: src/app.cpp src/app.h \
+               src/mainwin.h
+       $(CXX) -c $(CXXFLAGS) $(INCPATH) -o obj/app.o src/app.cpp
+
+obj/diskdrawthread.o: src/diskdrawthread.cpp src/diskdrawthread.h \
+               src/fileio.h \
+               src/global.h
+       $(CXX) -c $(CXXFLAGS) $(INCPATH) -o obj/diskdrawthread.o src/diskdrawthread.cpp
+
+obj/diskwidget.o: src/diskwidget.cpp src/diskwidget.h \
+               src/analysisthread.h \
+               src/diskdrawthread.h \
+               src/fileio.h \
+               src/global.h
+       $(CXX) -c $(CXXFLAGS) $(INCPATH) -o obj/diskwidget.o src/diskwidget.cpp
+
+obj/dsp.o: src/dsp.cpp src/dsp.h \
+               src/fileio.h \
+               src/global.h
+       $(CXX) -c $(CXXFLAGS) $(INCPATH) -o obj/dsp.o src/dsp.cpp
+
+obj/fileio.o: src/fileio.cpp src/fileio.h
+       $(CXX) -c $(CXXFLAGS) $(INCPATH) -o obj/fileio.o src/fileio.cpp
+
+obj/global.o: src/global.cpp src/global.h \
+               src/fileio.h
+       $(CXX) -c $(CXXFLAGS) $(INCPATH) -o obj/global.o src/global.cpp
+
+obj/infowidget.o: src/infowidget.cpp src/infowidget.h \
+               src/fileio.h \
+               src/global.h
+       $(CXX) -c $(CXXFLAGS) $(INCPATH) -o obj/infowidget.o src/infowidget.cpp
+
+obj/mainwidget.o: src/mainwidget.cpp src/mainwidget.h \
+               src/diskwidget.h \
+               src/nibblewidget.h \
+               src/waveformwidget.h
+       $(CXX) -c $(CXXFLAGS) $(INCPATH) -o obj/mainwidget.o src/mainwidget.cpp
+
+obj/mainwin.o: src/mainwin.cpp src/mainwin.h \
+               src/diskwidget.h \
+               src/fileio.h \
+               src/global.h \
+               src/infowidget.h \
+               src/mainwidget.h \
+               src/navwidget.h \
+               src/nibblewidget.h \
+               src/waveformwidget.h
+       $(CXX) -c $(CXXFLAGS) $(INCPATH) -o obj/mainwin.o src/mainwin.cpp
+
+obj/navwidget.o: src/navwidget.cpp src/navwidget.h \
+               src/fileio.h \
+               src/global.h
+       $(CXX) -c $(CXXFLAGS) $(INCPATH) -o obj/navwidget.o src/navwidget.cpp
+
+obj/nibblewidget.o: src/nibblewidget.cpp src/nibblewidget.h \
+               src/fileio.h \
+               src/global.h
+       $(CXX) -c $(CXXFLAGS) $(INCPATH) -o obj/nibblewidget.o src/nibblewidget.cpp
+
+obj/waveformwidget.o: src/waveformwidget.cpp src/waveformwidget.h \
+               src/dsp.h \
+               src/fileio.h \
+               src/global.h
+       $(CXX) -c $(CXXFLAGS) $(INCPATH) -o obj/waveformwidget.o src/waveformwidget.cpp
+
+obj/qrc_resources.o: obj/qrc_resources.cpp 
+       $(CXX) -c $(CXXFLAGS) $(INCPATH) -o obj/qrc_resources.o obj/qrc_resources.cpp
+
+obj/moc_analysisthread.o: obj/moc_analysisthread.cpp 
+       $(CXX) -c $(CXXFLAGS) $(INCPATH) -o obj/moc_analysisthread.o obj/moc_analysisthread.cpp
+
+obj/moc_diskdrawthread.o: obj/moc_diskdrawthread.cpp 
+       $(CXX) -c $(CXXFLAGS) $(INCPATH) -o obj/moc_diskdrawthread.o obj/moc_diskdrawthread.cpp
+
+obj/moc_diskwidget.o: obj/moc_diskwidget.cpp 
+       $(CXX) -c $(CXXFLAGS) $(INCPATH) -o obj/moc_diskwidget.o obj/moc_diskwidget.cpp
+
+obj/moc_infowidget.o: obj/moc_infowidget.cpp 
+       $(CXX) -c $(CXXFLAGS) $(INCPATH) -o obj/moc_infowidget.o obj/moc_infowidget.cpp
+
+obj/moc_mainwidget.o: obj/moc_mainwidget.cpp 
+       $(CXX) -c $(CXXFLAGS) $(INCPATH) -o obj/moc_mainwidget.o obj/moc_mainwidget.cpp
+
+obj/moc_mainwin.o: obj/moc_mainwin.cpp 
+       $(CXX) -c $(CXXFLAGS) $(INCPATH) -o obj/moc_mainwin.o obj/moc_mainwin.cpp
+
+obj/moc_navwidget.o: obj/moc_navwidget.cpp 
+       $(CXX) -c $(CXXFLAGS) $(INCPATH) -o obj/moc_navwidget.o obj/moc_navwidget.cpp
+
+obj/moc_nibblewidget.o: obj/moc_nibblewidget.cpp 
+       $(CXX) -c $(CXXFLAGS) $(INCPATH) -o obj/moc_nibblewidget.o obj/moc_nibblewidget.cpp
+
+obj/moc_waveformwidget.o: obj/moc_waveformwidget.cpp 
+       $(CXX) -c $(CXXFLAGS) $(INCPATH) -o obj/moc_waveformwidget.o obj/moc_waveformwidget.cpp
+
+####### Install
+
+install:  FORCE
+
+uninstall:  FORCE
+
+FORCE:
+
diff --git a/cross-compile b/cross-compile
new file mode 100755 (executable)
index 0000000..d3e9e66
--- /dev/null
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# Short script to do cross compilation with MXE on Linux
+#
+# by James Hammons
+# (C) 2012 Underground Software
+#
+TARGET=wozmaker
+#echo "Cross compiling ${TARGET} for Win32..."
+echo "Cross compiling ${TARGET} for Win64..."
+export PATH=/opt/mxe/usr/bin:$PATH
+rm Makefile
+
+#/opt/mxe/usr/bin/i686-w64-mingw32.static-qmake-qt5
+/opt/mxe/usr/bin/x86_64-w64-mingw32.static-qmake-qt5 \
+&& make clean && make -f Makefile.Release \
+&& rel=`git log -1 --pretty=format:%ci | cut -d ' ' -f 1 | tr -d -` \
+&& cd release && upx -9v ${TARGET}.exe && zip -9v ${TARGET}-${rel}.zip ${TARGET}.exe
+
diff --git a/res/resources.qrc b/res/resources.qrc
new file mode 100644 (file)
index 0000000..0e0ec1f
--- /dev/null
@@ -0,0 +1,6 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+       <file>woz-icon.png</file>
+</qresource>
+</RCC>
+
diff --git a/res/woz-icon.png b/res/woz-icon.png
new file mode 100644 (file)
index 0000000..7636626
Binary files /dev/null and b/res/woz-icon.png differ
diff --git a/src/analysisthread.cpp b/src/analysisthread.cpp
new file mode 100644 (file)
index 0000000..bd9daea
--- /dev/null
@@ -0,0 +1,63 @@
+//
+// analysisthread.cpp: Disk image analysis thread
+//
+// Part of the WOZ Maker project
+// by James Hammons
+// (C) 2018 Underground Software
+//
+// Since this can take a bit of time, we shunt all the heavy lifting to a
+// separate worker thread so that it doesn't block the GUI thread.
+//
+
+#include "analysisthread.h"
+
+#include <stdlib.h>
+#include <QtWidgets>
+#include <cmath>
+#include "dsp.h"
+#include "fileio.h"
+#include "global.h"
+
+
+AnalysisThread::AnalysisThread(QObject * parent): QThread(parent)
+{
+}
+
+
+AnalysisThread::~AnalysisThread()
+{
+#if 0
+       mutex.lock();
+       abort = true;
+       condition.wakeOne();
+       mutex.unlock();
+
+       wait();
+#endif
+}
+
+
+void AnalysisThread::StartAnalysis(void)
+{
+       start(LowPriority);
+}
+
+
+void AnalysisThread::run()
+{
+       // Sanity clause
+       if (Global::a2r == NULL)
+               return;
+
+//temp, until we get the AA filled ones sorted
+//     for(uint32_t i=0; i<141; i++)
+       for(uint32_t i=0; i<139; i++)
+       {
+               SynthesizeTrack(i);
+//             usleep(10000);
+               int a = random();
+               Global::trackStatus[i] = a & 0x03;
+               emit(ShowTracks());
+       }
+}
+
diff --git a/src/analysisthread.h b/src/analysisthread.h
new file mode 100644 (file)
index 0000000..ba4357e
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef __ANALYSISTHREAD_H__
+#define __ANALYSISTHREAD_H__
+
+//#include <QMutex>
+//#include <QSize>
+#include <QThread>
+//#include <QWaitCondition>
+
+//class QImage;
+
+class AnalysisThread: public QThread
+{
+       Q_OBJECT
+
+       public:
+               AnalysisThread(QObject * parent = 0);
+               ~AnalysisThread();
+
+               void StartAnalysis(void);
+
+       signals:
+               void ShowTracks(void);
+
+       protected:
+               void run() override;
+
+       private:
+//             void DrawDisk(QImage *);
+
+//             QImage * img;
+};
+
+#endif // __ANALYSISTHREAD_H__
+
diff --git a/src/app.cpp b/src/app.cpp
new file mode 100644 (file)
index 0000000..a7edd1b
--- /dev/null
@@ -0,0 +1,40 @@
+//
+// app.cpp: Implementation of the application
+//
+// Part of the WOZ Maker project
+// by James Hammons
+// (C) 2018 Underground Software
+// See the README and GPLv3 files for licensing and warranty information
+//
+
+#include "app.h"
+
+#include <QApplication>
+#include "mainwin.h"
+
+// Main app constructor--we stick globally accessible stuff here...
+
+App::App(int & argc, char * argv[]): QApplication(argc, argv)
+{
+       mainWindow = new MainWin;
+       mainWindow->show();
+}
+
+
+App::~App()
+{
+       delete mainWindow;
+}
+
+
+// Here's the main application loop--short and simple...
+int main(int argc, char * argv[])
+{
+       // This must the same name as the .qrc filename
+       Q_INIT_RESOURCE(resources);
+
+       App app(argc, argv);
+
+       return app.exec();
+}
+
diff --git a/src/app.h b/src/app.h
new file mode 100644 (file)
index 0000000..dc55148
--- /dev/null
+++ b/src/app.h
@@ -0,0 +1,20 @@
+#ifndef __APP_H__
+#define __APP_H__
+
+#include <QtWidgets>
+
+// Forward declarations
+class MainWin;
+
+class App: public QApplication
+{
+       public:
+               App(int & argc, char * argv[]);
+               ~App();
+
+       public:
+               MainWin * mainWindow;
+};
+
+#endif // __APP_H__
+
diff --git a/src/diskdrawthread.cpp b/src/diskdrawthread.cpp
new file mode 100644 (file)
index 0000000..f1e89e0
--- /dev/null
@@ -0,0 +1,128 @@
+//
+// diskdrawthread.cpp: Disk display thread
+//
+// Part of the WOZ Maker project
+// by James Hammons
+// (C) 2018 Underground Software
+//
+// Since this can take a bit of time, we shunt all the heavy lifting to a
+// separate worker thread so that it doesn't block the GUI thread.
+//
+
+#include "diskdrawthread.h"
+
+#include <QtWidgets>
+#include <cmath>
+#include "fileio.h"
+#include "global.h"
+
+
+DiskDrawThread::DiskDrawThread(QObject * parent): QThread(parent)
+{
+}
+
+
+DiskDrawThread::~DiskDrawThread()
+{
+#if 0
+       mutex.lock();
+       abort = true;
+       condition.wakeOne();
+       mutex.unlock();
+
+       wait();
+#endif
+}
+
+
+void DiskDrawThread::StartRender(QImage * i)
+{
+       img = i;
+       start(LowPriority);
+}
+
+
+void DiskDrawThread::run()
+{
+       DrawDisk(img);
+}
+
+
+void DiskDrawThread::DrawDisk(QImage * diskImg)
+{
+       QPainter painter(diskImg);
+       painter.setRenderHint(QPainter::Antialiasing);
+
+       QPen dkGreyPen(QColor(0x3A, 0x3B, 0x3A, 0xFF));
+       QBrush dkGreyBrush(QColor(0x3A, 0x3B, 0x3A, 0xFF));
+
+       // Draw empty disk
+       painter.setPen(dkGreyPen);
+       painter.setBrush(dkGreyBrush);
+       painter.drawEllipse(0, 0, 1024, 1024);
+       painter.setPen(Qt::white);
+       painter.setBrush(Qt::white);
+       painter.drawEllipse(388, 388, 248, 248);
+
+/*
+945 - 1067
+948-949 (brighter to the 949 side) 1063-1064 (brighter to the 1064 side)
+
+116 px for 36 tracks (3.2857... px per track)
+
+3px on each side of the tracks
+
+388 / 122 = 3.1803278688525
+qtr track width = 2.6836879432624
+*/
+       // Draw disk track data
+       uint8_t lastLocation = 0xFF;
+       float x = 9.6, y = 9.6, w = 1024.0 - (2.0 * 9.6);
+       float tw = 2.6156028368794;
+
+       for(uint32_t str=0; str<Global::numStreams; str++)
+       {
+//N.B.: Should also make sure this isn't a BITS stream, or handle it properly (because right now, it doesn't)
+               if (Global::stream[str]->location != lastLocation)
+               {
+                       uint32_t splicePoint = Uint32LE(Global::stream[str]->estLoopPoint);
+                       float angleTime = (float)splicePoint / (5760.0f / 2.0f);
+                       uint32_t pos = 0;
+                       float strTime = 0;
+                       float curTime = angleTime;
+
+                       for(uint32_t i=0; i<5760; i+=2)
+                       {
+                               float ones = 0;
+
+                               while (strTime < curTime)
+                               {
+                                       while (Global::stream[str]->data[pos] == 0xFF)
+                                               strTime += Global::stream[str]->data[pos++];
+
+                                       strTime += Global::stream[str]->data[pos++];
+                                       ones += 1.0f;
+                               }
+
+                               uint32_t color = ((ones * 32.0f) / angleTime) * 255.0f;
+
+                               if (color > 255)
+                                       color = 255;
+
+                               painter.setPen(QPen(QColor(color, color, color, 0xFF), tw, Qt::SolidLine));
+                               painter.drawArc(x, y, w, w, -i + 1440, 2);
+
+                               curTime += angleTime;
+                       }
+
+                       x += tw;
+                       y += tw;
+                       w -= tw * 2.0;
+                       lastLocation = Global::stream[str]->location;
+                       emit(ShowDisk());
+               }
+       }
+
+//     emit(ShowDisk());
+}
+
diff --git a/src/diskdrawthread.h b/src/diskdrawthread.h
new file mode 100644 (file)
index 0000000..e7ee4bc
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef __DISKDRAWTHREAD_H__
+#define __DISKDRAWTHREAD_H__
+
+//#include <QMutex>
+//#include <QSize>
+#include <QThread>
+//#include <QWaitCondition>
+
+class QImage;
+
+class DiskDrawThread: public QThread
+{
+       Q_OBJECT
+
+       public:
+               DiskDrawThread(QObject * parent = 0);
+               ~DiskDrawThread();
+
+               void StartRender(QImage *);
+
+       signals:
+               void ShowDisk(void);
+
+       protected:
+               void run() override;
+
+       private:
+               void DrawDisk(QImage *);
+
+               QImage * img;
+};
+
+#endif // __DISKDRAWTHREAD_H__
+
diff --git a/src/diskwidget.cpp b/src/diskwidget.cpp
new file mode 100644 (file)
index 0000000..0c5b2ad
--- /dev/null
@@ -0,0 +1,267 @@
+//
+// diskwidget.cpp: Disk display widget
+//
+// Part of the WOZ Maker project
+// by James Hammons
+// (C) 2018 Underground Software
+//
+
+#include "diskwidget.h"
+#include "analysisthread.h"
+#include "diskdrawthread.h"
+#include "fileio.h"
+#include "global.h"
+
+
+enum { green = 0, yellow, red, grey, dkGrey, ltGrey };
+
+
+static inline int ColorForTrack(uint8_t num)
+{
+       int trackColor;
+
+       switch (num)
+       {
+       case 1:
+               trackColor = green;
+               break;
+       case 2:
+               trackColor = yellow;
+               break;
+       case 3:
+               trackColor = red;
+               break;
+       default:
+               trackColor = grey;
+       }
+
+       return trackColor;
+}
+
+
+DiskWidget::DiskWidget(QWidget * parent/*= 0*/): QWidget(parent)
+{
+       setGeometry(QRect(0, 0, 1290, 340));
+       setMinimumWidth(1290);
+       setMinimumHeight(340);
+       setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+       diskImg = new QImage(1024, 1024, QImage::Format_ARGB32);
+       DrawDisk();
+}
+
+
+DiskWidget::~DiskWidget(void)
+{
+       delete diskImg;
+}
+
+
+void DiskWidget::HandleUpdate(void)
+{
+       update();
+}
+
+
+void DiskWidget::paintEvent(QPaintEvent * /*event*/)
+{
+       QPainter painter(this);
+       painter.setRenderHint(QPainter::Antialiasing);
+
+//     QFont font("Monospace"); // ugly
+//     QFont font("DejaVu Sans Mono"); // ugly
+       QFont font("Hack");
+       font.setPixelSize(10);
+       font.setWeight(QFont::Normal);
+       font.setHintingPreference(QFont::PreferFullHinting);
+       font.setStyleHint(QFont::Monospace);
+       painter.setFont(font);
+
+       QColor color[6] = {
+               QColor(0x74, 0xC1, 0x60, 0xFF),         // Green
+               QColor(0xFA, 0xC3, 0x48, 0xFF),         // Yellow
+               QColor(0xE4, 0x4D, 0x54, 0xFF),         // Red
+               QColor(0xD6, 0xDC, 0xD7, 0xFF),         // Grey
+               QColor(0x3A, 0x3B, 0x3A, 0xFF),         // Dk. Grey
+               QColor(0xE9, 0xE9, 0xE3, 0xFF)          // Lt. Grey
+       };
+
+       QBrush brush[6] = {
+               QBrush(color[0]),
+               QBrush(color[1]),
+               QBrush(color[2]),
+               QBrush(color[3]),
+               QBrush(color[4]),
+               QBrush(color[5])
+       };
+
+       QPen pen1[6] = {
+               QPen(color[0], 1.0),
+               QPen(color[1], 1.0),
+               QPen(color[2], 1.0),
+               QPen(color[3], 1.0),
+               QPen(color[4]),
+               QPen(color[5])
+       };
+
+       QPen pen2[6] = {
+               QPen(color[0], 2.0),
+               QPen(color[1], 2.0),
+               QPen(color[2], 2.0),
+               QPen(color[3], 2.0),
+               QPen(color[4], 2.0),
+               QPen(color[5], 2.0)
+       };
+
+       QPolygonF poly[4];
+       poly[0] << QPointF(-0.5, -0.5) << QPointF(18.5, -0.5) << QPointF(18.5, 17.5) << QPointF(-0.5, 26.5);
+       poly[1] << QPointF(6, 30) << QPointF(19, 24) << QPointF(19, 47) << QPointF(6, 53);
+       poly[2] << QPointF(6, 58) << QPointF(19, 52) << QPointF(19, 75) << QPointF(6, 81);
+       poly[3] << QPointF(6, 86) << QPointF(19, 80) << QPointF(19, 107) << QPointF(6, 107);
+
+       QPointF start(70.0, 62.0);
+
+       // Draw disk track data image
+       painter.drawImage(QRect(922, 8, 326, 326), diskImg->scaled(326, 326, Qt::KeepAspectRatio, Qt::SmoothTransformation));
+
+       // Draw quarter track legend
+       QRectF qtl = QRectF(start.x() - 29.0, start.y(), 29.0, 24.0);
+       painter.setPen(pen1[dkGrey]);
+       painter.drawText(qtl.translated(0.0, 0.0), Qt::AlignCenter, ".00");
+       painter.drawText(qtl.translated(0.0, 28.0), Qt::AlignCenter, ".25");
+       painter.drawText(qtl.translated(0.0, 56.0), Qt::AlignCenter, ".50");
+       painter.drawText(qtl.translated(0.0, 84.0), Qt::AlignCenter, ".75");
+
+       for(uint32_t i=0; i<36; i++)
+       {
+               QRectF trkArc(start.x() + ((float)i * 24.0), 8.0, 326.0, 326.0);
+
+               int trackColor = ColorForTrack(Global::trackStatus[i * 4]);
+
+               painter.setPen(pen2[trackColor]);
+               painter.drawLine(start.x() + (i * 24.0), start.y(), start.x() + (i * 24.0), start.y() + 112.0f);
+               painter.drawArc(trkArc, 180 * 16, 45 * 16);
+
+               painter.setPen(pen1[trackColor]);
+               painter.setBrush(brush[trackColor]);
+               painter.drawPolygon(poly[0].translated(start.x() + ((float)i * 24.0), start.y()));
+
+               painter.setPen(pen1[dkGrey]);
+               painter.drawText(start.x() + (i * 24.0), start.y() - 17.0, 20.0, 16.0, Qt::AlignCenter, QString("%1").arg((ushort)i, 2, 16, QChar('0')).toUpper());
+
+               // Make sure we don't draw too many quarter tracks (e.g., none on 35)
+               if (i == 35)
+                       continue;
+
+               for(uint32_t j=1; j<4; j++)
+               {
+                       trackColor = ColorForTrack(Global::trackStatus[(i * 4) + j]);
+
+                       painter.setBrush(brush[trackColor]);
+                       painter.setPen(pen1[trackColor]);
+                       painter.drawPolygon(poly[j].translated(69.5 + (i * 24.0), 61.5));
+                       painter.setPen(pen2[trackColor]);
+                       painter.drawArc(trkArc.translated(6 * j, 0), 181 * 16, 40 * 16);
+               }
+       }
+}
+
+
+void DiskWidget::DrawDisk(void)
+{
+       DiskDrawThread * ddt = new DiskDrawThread(this);
+       connect(ddt, &DiskDrawThread::ShowDisk, this, &DiskWidget::HandleUpdate);
+       connect(ddt, &DiskDrawThread::finished, ddt, &QObject::deleteLater);
+       ddt->StartRender(diskImg);
+
+       AnalysisThread * at = new AnalysisThread(this);
+       connect(at, &AnalysisThread::ShowTracks, this, &DiskWidget::HandleUpdate);
+       connect(at, &AnalysisThread::finished, at, &QObject::deleteLater);
+       at->StartAnalysis();
+}
+
+
+//
+// Decode which track is being pointed at, and update everything
+//
+void DiskWidget::mousePressEvent(QMouseEvent * event)
+{
+       if (event->button() == Qt::LeftButton)
+       {
+               int32_t x = event->x(), y = event->y();
+
+               if ((x >= 70) && (x <= 934) && (y >= 62) && (y <= 169))
+               {
+                       int32_t startx = (x - 70) / 24;
+                       int32_t starty = (x <= 910 ? (y - 62) / 27 : 0);
+
+                       Global::trackNum = (startx * 4) + starty;
+                       emit(UpdateWaveform());
+                       emit(UpdateInfo());
+               }
+
+               event->accept();
+       }
+}
+
+
+void DiskWidget::mouseMoveEvent(QMouseEvent * event)
+{
+       if (event->buttons() & Qt::LeftButton)
+       {
+               event->accept();
+       }
+}
+
+
+void DiskWidget::mouseReleaseEvent(QMouseEvent * event)
+{
+       if (event->button() == Qt::LeftButton)
+       {
+               event->accept();
+       }
+}
+
+
+void DiskWidget::mouseDoubleClickEvent(QMouseEvent * event)
+{
+       if (event->button() == Qt::LeftButton)
+       {
+               event->accept();
+       }
+}
+
+
+void DiskWidget::keyPressEvent(QKeyEvent * event)
+{
+       int key = event->key();
+
+       if (key == Qt::Key_Up)
+       {
+       }
+       else if (key == Qt::Key_Down)
+       {
+       }
+       else if (key == Qt::Key_Left)
+       {
+       }
+       else if (key == Qt::Key_Right)
+       {
+       }
+       else
+               return;
+
+       // Only update if a key we recognize has been pressed!
+       update();
+}
+
+
+void DiskWidget::keyReleaseEvent(QKeyEvent * /*event*/)
+{
+}
+
+
+void DiskWidget::resizeEvent(QResizeEvent * /*event*/)
+{
+//     ResizeGrid();
+}
+
diff --git a/src/diskwidget.h b/src/diskwidget.h
new file mode 100644 (file)
index 0000000..9bb0301
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef __DISKWIDGET_H__
+#define __DISKWIDGET_H__
+
+#include <QtWidgets>
+//#include <stdint.h>
+
+class DiskWidget: public QWidget
+{
+       Q_OBJECT
+
+       public:
+               DiskWidget(QWidget * parent = 0);
+               ~DiskWidget();
+
+       signals:
+               void UpdateWaveform(void);
+               void UpdateInfo(void);
+
+       public slots:
+               void HandleUpdate(void);
+
+       protected:
+               void paintEvent(QPaintEvent * event);
+               void mousePressEvent(QMouseEvent * event);
+               void mouseMoveEvent(QMouseEvent * event);
+               void mouseReleaseEvent(QMouseEvent * event);
+               void mouseDoubleClickEvent(QMouseEvent * event);
+               void keyPressEvent(QKeyEvent * event);
+               void keyReleaseEvent(QKeyEvent * event);
+               void resizeEvent(QResizeEvent * event);
+
+       public:
+               void DrawDisk(void);
+
+       private:
+               QImage * diskImg;
+};
+
+#endif // __DISKWIDGET_H__
+
diff --git a/src/dsp.cpp b/src/dsp.cpp
new file mode 100644 (file)
index 0000000..98800a2
--- /dev/null
@@ -0,0 +1,2935 @@
+//
+// dsp.cpp: Digital Signal Processing module
+//
+// Part of the WOZ Maker project
+// by James Hammons
+// (C) 2018 Underground Software
+//
+
+#include "dsp.h"
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+#include "fileio.h"
+#include "global.h"
+
+
+//#define NOISY
+
+// Really, there shouldn't be more than 5 waveforms per track
+//static uint32_t total = 0;//trkStrms
+//static uint32_t slip[9];
+//double ratio[9];
+uint32_t sNum[9];
+double initSyncTime[9];
+
+static const double SIGMA_THRESHOLD = 2.5;
+
+
+double StdDeviation(double * a, uint32_t num, double * pMean/*= NULL*/)
+{
+       double sigma = 0, mean = 0;
+
+       for(uint32_t i=0; i<num; i++)
+               mean += a[i];
+
+       mean = mean / (double)num;
+
+       if (pMean)
+               *pMean = mean;
+
+       for(uint32_t i=0; i<num; i++)
+               sigma += (a[i] - mean) * (a[i] - mean);
+
+       sigma *= 1.0 / (double)num;
+       return sqrt(sigma);
+}
+
+
+double StdDeviationWave(uint32_t * sync, uint32_t num, double * m = NULL);
+double StdDeviationWave(uint32_t * sync, uint32_t num, double * m/*= NULL*/)
+{
+       double sigma = 0, mean = 0;
+       double a[7];
+
+       for(uint32_t i=0; i<num; i++)
+       {
+               a[i] = (double)Global::wave[sNum[i]][sync[i]];
+               mean += a[i];
+       }
+
+       mean = mean / (double)num;
+
+       // Capture the mean, if a pointer was passed in
+       if (m)
+               *m = mean;
+
+       for(uint32_t i=0; i<num; i++)
+               sigma += (a[i] - mean) * (a[i] - mean);
+
+       return sqrt(sigma / (double)num);
+}
+
+
+double Largest(double * a, uint32_t num)
+{
+       double largest = a[0];
+
+       for(uint32_t i=1; i<num; i++)
+       {
+               if (a[i] > largest)
+                       largest = a[i];
+       }
+
+       return largest;
+}
+
+
+uint32_t Largest(uint32_t * a, uint32_t num)
+{
+       uint32_t largest = a[0];
+
+       for(uint32_t i=1; i<num; i++)
+       {
+               if (a[i] > largest)
+                       largest = a[i];
+       }
+
+       return largest;
+}
+
+
+uint32_t LargestIndex(double * a, uint32_t num)
+{
+       double largest = a[0];
+       uint32_t index = 0;
+
+       for(uint32_t i=1; i<num; i++)
+       {
+               if (a[i] > largest)
+               {
+                       largest = a[i];
+                       index = i;
+               }
+       }
+
+       return index;
+}
+
+
+uint32_t LargestIndex(uint32_t * a, uint32_t num)
+{
+       uint32_t largest = a[0];
+       uint32_t index = 0;
+
+       for(uint32_t i=1; i<num; i++)
+       {
+               if (a[i] > largest)
+               {
+                       largest = a[i];
+                       index = i;
+               }
+       }
+
+       return index;
+}
+
+
+double Smallest(double * a, uint32_t num)
+{
+       double smallest = a[0];
+
+       for(uint32_t i=1; i<num; i++)
+       {
+               if (a[i] < smallest)
+                       smallest = a[i];
+       }
+
+       return smallest;
+}
+
+
+uint32_t Smallest(uint32_t * a, uint32_t num)
+{
+       uint32_t smallest = a[0];
+
+       for(uint32_t i=1; i<num; i++)
+       {
+               if (a[i] < smallest)
+                       smallest = a[i];
+       }
+
+       return smallest;
+}
+
+
+uint32_t SmallestIndex(double * a, uint32_t num)
+{
+       double smallest = a[0];
+       uint32_t index = 0;
+
+       for(uint32_t i=1; i<num; i++)
+       {
+               if (a[i] < smallest)
+               {
+                       smallest = a[i];
+                       index = i;
+               }
+       }
+
+       return index;
+}
+
+
+uint32_t SmallestIndex(uint32_t * a, uint32_t num)
+{
+       uint32_t smallest = a[0];
+       uint32_t index = 0;
+
+       for(uint32_t i=1; i<num; i++)
+       {
+               if (a[i] < smallest)
+               {
+                       smallest = a[i];
+                       index = i;
+               }
+       }
+
+       return index;
+}
+
+
+//
+// This is where we attempt to use the stream data to collapse them down to a single track.  Taken as wholes, each individual track will drift out of sync with respect to the others, and fairly quickly as the drive mechanism does not read consistently at a set RPM as you might expect, but instead it fluctuates all over the place--which throws a big ol' monkey wrench into the works.  (Yes, the overall *average* stays around a set RPM, but locally--nope.)
+//
+// The big problem is that the disk spins via a motor which isn't perfect in its rotation that is connected to the hub that spins the disk via a belt, which further adds more uncertainty to the speed of the disk as it rotates.  The end result is that there is no consistency vis-a-vis the speed of the disk, and so the results of one read to the next can and will vary wildly.  It's a miracle that these things are readable at all.  O_o
+//
+// So how do we cope with it?  I'm sure there's a well known paper or set of papers which addresses noise rejection from multiple signals read from a single source, but I have yet to find them.  So what we have below is a set of ad-hoc assumptions and heuristics that attempt to deal with this problem.
+//
+// The basic assumption is that from any given pulse to the next one, the drift will tend to be small and thus as we move from pulse to pulse, we can stay more or less in sync by resetting the base from which we calculate the next time interval to the previous step.  This works remarkably well until we run into a long period of zeroes, which seems to throw off the Applesauce hardware which read these streams in the first place; or when some spurious one pulses pop up in one stream that doesn't in one or more of the others.
+//
+#if 0
+uint32_t Synthesize(uint32_t * sync, uint32_t num, uint32_t * synthWave, float * swAmplitude)
+{
+       uint32_t swLen = 0;
+       uint32_t syncPt[9], syncSave[9], nrSync[9];
+       double a[9], currentRow[9], nextRow[9];
+       double time[9][32], drift[9];
+       uint32_t timePtr = 0;
+
+       memcpy(syncPt, sync, sizeof(syncPt));
+
+       while (true)
+       {
+               for(uint32_t i=0; i<num; i++)
+               {
+                       if (syncPt[i] >= Global::streamLen[i])
+                               return swLen;
+               }
+
+               // Save these *before* we step forward
+               memcpy(syncSave, syncPt, sizeof(syncSave));
+               StepForward(syncPt, a, num);
+               double mean;
+               double sigma = StdDeviation(a, num, &mean);
+
+               if (sigma <= SIGMA_THRESHOLD)
+               {
+                       for(uint32_t i=0; i<num; i++)
+                               time[i][timePtr] = a[i];
+
+                       timePtr = (timePtr + 1) % 32;
+
+                       synthWave[swLen] = (uint32_t)(mean + 0.5);
+                       swAmplitude[swLen] = 1.0f;
+                       swLen++;
+               }
+               else
+               {
+                       // Calculate drift over the last 32 time steps...
+                       for(uint32_t i=0; i<num; i++)
+                       {
+                               drift[i] = 0;
+
+                               for(uint32_t j=0; j<32; j++)
+                                       drift[i] += time[i][j];
+                       }
+
+                       double driftSigma = StdDeviation(drift, num);
+                       memcpy(nrSync, syncPt, sizeof(nrSync));
+                       StepForward(nrSync, nextRow, num);
+                       double nextSigma = StdDeviation(nextRow, num);
+                       uint32_t lookahead = Lookahead(nrSync, num, +1);
+
+                       // The basic idea is to find the extent of this anomalous region and then use what's there as an amplitude by summing the signals where they correspond.
+//                     memcpy(syncSave, syncPt, sizeof(syncSave));
+                       bool pulled, doSync = true;
+                       uint32_t syncSteps = 0;
+
+                       // Basically we move forward thru the area until either 1) the sigma is OK, or 2) we've pulled everything as far as it can go and thus this becomes our new local start. 3) will go in at some point which is, do a lookahead and see what the sigma looks like; if it's good and the current one is stinko, (not *too* stinko) then we've found a new local start point, otherwise keep going.
+/*
+Note that 3) works OK to get out of sticky situations, but sometimes the signals are fairly noisy and you will end up in situations where the lookahead is zero and the next sigma isn't great (& the current isn't any good either), but using that as the new local start is OK and will permit walking forward/backward through the stream.  Some of the time you will find the average of the current sigma and the following will be below the threshold with a good lookahead value (10, 100, 1000), this is also a good time to set the new local start.
+*/
+#ifdef NOISY
+printf("a: ");
+for(uint32_t i=0; i<num; i++)
+       printf("[%.2lf]", a[i]);
+printf(" => %.2lf {drift=%.2lf, la=%d}\n", sigma, driftSigma, lookahead);
+#endif
+                       // New heuristic: if the sigma of the current row is less than the sigma of the drift over the last 32 steps, we consider that to be "in sync"; otherwise, do the usual stuff
+/*
+This works until you hit this:
+a: [1167.00][1174.00][1169.00] => 2.94
+          ~~~~
+<1167.00><1174.00><1169.00> ==> 2.94 {drift=0.82}(!!!) (lookahead=2.94, 630)
+{12168}-{12166}-{12166}
+          ~~~~
+<1198.00><1205.00><1200.00> ==> 2.94 {drift=0.82} (lookahead=0.00, 629)
+{12169}-{12167}-{12167}
+          ~~~~
+<1231.00><1238.00><1233.00> ==> 2.94 {drift=0.82} (lookahead=0.00, 628)
+----------------
+<337.00><334.00><335.00> ==> 1.25 (OK) (lookahead=18.40, 1705)
+{1260}-{1259}-{1258}
+a: [1111.00][1100.00][1097.00] => 6.02 {drift=7.72, la=0}
+a: [42.00][51.00][45.00] => 3.74 {drift=7.72, la=150}
+  20.00   ~~~~     0.00
+< 62.00>< 51.00>< 45.00> ==> 7.04 (lookahead=13.42, 0)
+{2972}-{2970}-{2969}
+  ~~~~    20.00   13.00 <-- the more I look at it, the more I think we need to coalesce these into their next steps... (can be done in StepForward/Back())
+-------------------
+it does OK but fails because we don't check *inside* the loop
+<363.00><364.00><364.00> ==> 0.47 (OK) (lookahead=52.33, 1704)
+{25947}-{25931}-{25922}
+a: [33.00][15.00][47.00] => 13.10 {drift=3.86, la=150}
+ 1149.00  1158.00   ~~~~
+<1182.00><1173.00>< 47.00> ==> 532.94 (lookahead=40.94, 0)
+{27657}-{27641}-{27627}
+  ~~~~    31.00  1155.00
+<1182.00><1204.00><1202.00> ==> 9.93 (lookahead=46.20, 6)
+{27657}-{27642}-{27633}
+  31.00   ~~~~     0.00
+<1213.00><1204.00><1202.00> ==> 4.78 (lookahead=0.00, 149)
+{27658}-{27642}-{27633}
+
+*/
+                       // We check for large zero areas for the new heuristic
+//buuuuuuuut... it fails for the stuff that tags along at the end, so...
+/*
+After looking at this long and hard, and thinking about the fairly random nature of the disk speed as it turns, I've come to the conclusion that trying to use the local speed drift (whatever that means) is futile.  It's random; it just doesn't correlate, period.  So stuff like the following is pretty much crap.
+*/
+                       if ((mean > 9.0)//00.0)
+                               && ((sigma < StdDeviation(drift, num))
+                                       || (((sigma + nextSigma) / 2.0) < SIGMA_THRESHOLD)))
+                       {
+                               doSync = false;
+                       }
+
+                       if (doSync)
+                       {
+                               do
+                               {
+                                       syncSteps++;
+
+                                       // If we've been in this loop too long, something's very wrong
+                                       if (syncSteps > 20)
+                                               return swLen;
+
+                                       // Pull the lesser streams forward to catch up to the largest
+                                       uint32_t largestIdx = LargestIdx(a, num);
+                                       pulled = false;
+
+                                       for(uint32_t i=0; i<num; i++)
+                                       {
+                                               if (i == largestIdx)
+#ifdef NOISY
+                                               {
+                                                       printf("  ~~~~  ");
+#endif
+                                                       continue;
+#ifdef NOISY
+                                               }
+#endif
+
+                                               double ttn = 0;
+                                               uint32_t walkahead = syncPt[i];
+
+                                               while ((a[largestIdx] - (a[i] + ttn)) > 7.0)
+                                               {
+                                                       pulled = true;
+
+                                                       if (walkahead >= Global::streamLen[i])
+                                                       {
+                                                               // We ran out of road, so we're done for now
+                                                               return swLen;
+                                                       }
+/*
+Maybe rename this to StepForwardSngl and the other to StepForwardAll?
+because otherwise, this can become murky
+[well, should be able to tell from the context.
+well, the thing that's murky is the all clears the array while the single adds to the existing.  now *that's* confusing...  :-P]
+we can call it StepAndAddForward/Back; that would clear it up.
+*/
+                                                       StepAndAddForward(walkahead, ttn, i);
+                                               }
+
+                                               syncPt[i] = walkahead;
+                                               a[i] += ttn;
+#ifdef NOISY
+                                               if (pulled)
+                                                       printf(" %6.2lf ", ttn);
+                                               else
+                                                       printf("        ");
+#endif
+                                       }
+
+#ifdef NOISY
+                                       printf("\n");
+
+                                       for(uint32_t i=0; i<num; i++)
+                                               printf("<%6.2lf>", a[i]);
+#endif
+                                       // Calculate the standard deviation at this new point
+                                       sigma = StdDeviation(a, num, &mean);
+#ifdef NOISY
+                                       printf(" ==> %.2lf%s", sigma, (sigma <= SIGMA_THRESHOLD ? " (OK)" : (!pulled ? "(STEP)" : "")));
+
+double lookahead[9];
+//printf(" {drift=%.2lf}", driftSigma);
+uint32_t minSyncIdx = SmallestIdx(syncPt, num);
+if (syncPt[minSyncIdx] > 0)
+{
+       for(uint32_t i=0; i<num; i++)
+               lookahead[i] = (double)Global::streamData[i][syncPt[i] + 0] * ratio[i];
+       printf(" (lookahead=%.2lf, %d)\n", StdDeviation(lookahead, num), Lookahead(syncPt, num, +1));
+}
+else
+       printf("\n");
+
+for(uint32_t j=0; j<num; j++) { printf("{%d}%s", syncPt[j], (j < num - 1 ? "-" : "")); }
+printf("\n");
+#endif
+
+                                       // Heuristic: see if we're stuck with a bad sigma and can't pull any more forward; if so, pull forward one step and see if that gets us any traction...
+                                       if ((sigma > SIGMA_THRESHOLD) && !pulled)
+                                       {
+                                               for(uint32_t i=0; i<num; i++)
+                                                       StepAndAddForward(syncPt[i], a[i], i);
+
+                                               sigma = StdDeviation(a, num, &mean);
+                                               pulled = true;
+                                       }
+                               }
+                               while ((sigma > SIGMA_THRESHOLD) && pulled);
+                       }
+
+                       // Now, we've re-established sync, now fill the appropriate spots
+
+/*
+So the algorithm to do this proppaly is like so:
+
+Step 1: Find the smallest step forward through the section; set amplitude to 0.2.
+Step 2: Loop thru the other streams and see if they correspond.  If so, advance their stream start & add 0.2 to the amplitude for each one seen.
+Step 3: Add the mean value of the corresponding values to the synthesized waveform + wave amplitude
+Step 4: If all of the stream starts are at the end of the section, we are done.
+[maybe.  how do you handle the case where you have streams that look like so:
+
+200
+150 50
+150 50
+175 25
+200
+
+.......................................|
+.............................|.........|
+.............................|.........|
+..................................|....|
+.......................................|
+
+this will fail to add in the correct amount for the times that had no part in the anomaly.  so to fix this, maybe have a baseline value that bumps upward to show where the "cursor" (so to speak) is, so at the end we can subtract the mean that we got above from this baseline to get the remaining time to synthesize, like so:
+
+synthWave[swLen] = (uint32_t)((mean - baseline) + 0.5)
+swAmplitude[swLen] = amplitude;
+
+no need for that.  the times that step directly to the end can safely be ignored.
+]
+
+150 -> 150 (ignores 175)
+150 goes in, ampl. .4, we now have:
+
+200
+50
+50
+175 25
+200
+
+only one is left that we can grab:
+
+175
+
+last pulse was at 150 (40%), so we need to subtract that out
+
+-> 25
+
+so maybe we'd do like so:
+-1) create a list containing the start values for the start of the anomalous section and replace them as the counters advance.
+0) are streams at the end? if so, stuff in the final value to the synthesized wave & stop, otherwise:
+1) find the smallest in the current row and use that as a basis.
+2) find streams that correlate, if any
+3) advance the streams that correlate & subtract out the minimum from the other rows
+4) go to 0)
+
+200
+150 50
+150 50
+175 25
+200
+
+smallest is 150: pick 150 -> picks up 150
+advance the 150 rows & subtract 150 from the rest:
+
+50
+50
+50
+25 25
+50
+
+pick smallest: 25 -> picks up nothing
+advance the 25 & subtract it from the rest:
+
+25
+25
+25
+25
+25
+
+We've reached the end of the section, add the final amount
+
+--------------------------------------------------------------------------------
+syncSave before: [2->4][2->6][2->4][2->6][2->6]
+syncSave after: [3->4][3->6][3->4][3->6][3->6]
+
+currentRow: [120.89][49.97][46.98][49.98][48.98] => 28.78
+
+2: [3->4][3->6][3->4][3->6][3->6]
+
+a[0]=46.98: [120.89] ==> 36.95
+        [49.97]{17.00} ==> 1.50
+        <106.00>[49.97][49.98]{28.00} ==> 1.41
+        [49.97][49.98][48.98]{26.00} ==> 1.22
+
+3: [3->4][4->6][4->4][4->6][4->6]
+
+a[0]=17.00: [73.91] ==> 28.45
+        <56.00>[28.00]{45.00} ==> 5.50
+        [28.00][26.00]{47.00} ==> 4.78
+
+4: [3->4][5->6][4->4][5->6][5->6]
+
+a[0]=45.00: [56.91] ==> 5.95
+        [56.00]{32.00} ==> 5.50
+        <32.00>[56.00][47.00]{32.00} ==> 4.78
+
+5: [3->4][6->6][4->4][6->6][6->6]
+
+a[0]=11.91: <32.00>
+
+6: [4->4][6->6][4->4][6->6][6->6]
+
+ 2->4    2->6    2->4    2->6    2->6
+[120.89][ 49.97][ 46.98][ 49.98][ 48.98] => 28.78
+( 73.91)  17.00  106.00   28.00   26.00
+( 56.91)  56.00           45.00   47.00
+  32.00   32.00           32.00   32.00
+
+*/
+/*printf("syncSave before: ");
+for(uint32_t i=0; i<num; i++)
+       printf("[%d->%d]", syncSave[i], syncPt[i]);
+printf("\n");//*/
+
+                       // Collect the current row
+                       StepForward(syncSave, currentRow, num);
+                       bool done2;
+                       float ampStep = 1.0f / (float)num;
+
+/*printf("syncSave after: ");
+for(uint32_t i=0; i<num; i++)
+       printf("[%d->%d]", syncSave[i], syncPt[i]);
+printf("\n");
+printf("currentRow: ");
+for(uint32_t i=0; i<num; i++)
+       printf("[%.2lf]", currentRow[i]);
+printf(" => %.2lf\n", StdDeviation(currentRow, num));//*/
+
+                       done2 = true;
+
+//printf("%d: ", swLen);
+                       for(uint32_t i=0; i<num; i++)
+                       {
+//printf("[%d->%d]", syncSave[i], syncPt[i]);
+                               if (syncSave[i] != syncPt[i])
+                               {
+                                       done2 = false;
+//                                     break;
+                               }
+                       }
+//printf("\n");
+
+                       while (!done2)
+                       {
+                               float amplitude = ampStep;
+                               uint32_t smallestIdx = SmallestIdx(currentRow, num);
+                               uint32_t cnt = 1;
+                               a[0] = currentRow[smallestIdx];
+//printf("a[0]=%.2lf: ", a[0]);
+
+                               for(uint32_t i=0; i<num; i++)
+                               {
+                                       // Make sure we haven't gone beyond the end of any of the streams we're looking at
+                                       if (syncSave[i] >= Global::streamLen[i])
+                                               return swLen;
+
+                                       if (i == smallestIdx)
+                                       {
+                                               currentRow[i] = 0;
+                                               StepAndAddForward(syncSave[i], currentRow[i], i);
+//printf("<%.2lf>", currentRow[i]);
+
+                                               // Make sure no spurious signals are looked at
+                                               if ((syncSave[i] < syncPt[i]) && (currentRow[i] < 24.0))
+                                                       StepAndAddForward(syncSave[i], currentRow[i], i);
+
+                                               continue;
+                                       }
+
+                                       double crSave = currentRow[i];
+                                       currentRow[i] -= a[0];
+
+                                       // Don't bother with stuff that's out of range!  :-P
+                                       if (syncSave[i] == syncPt[i])
+                                               continue;
+
+                                       // Try to find correlates
+                                       a[cnt] = crSave;//currentRow[i];
+                                       cnt++;
+                                       sigma = StdDeviation(a, cnt, &mean);
+//for(uint32_t j=1; j<cnt; j++)
+//     printf("[%.2lf]", a[j]);
+
+//relaxed sigma...
+                                       if (sigma <= 5.5)//SIGMA_THRESHOLD)
+                                       {
+                                               currentRow[i] = 0;
+                                               StepAndAddForward(syncSave[i], currentRow[i], i);
+//printf("{%.2lf}", currentRow[i]);
+                                               amplitude += ampStep;
+
+                                               // Make sure no spurious signals are looked at
+                                               if ((syncSave[i] < syncPt[i]) && (currentRow[i] < 24.0))
+                                                       StepAndAddForward(syncSave[i], currentRow[i], i);
+                                       }
+                                       else
+                                       {
+                                               cnt--;
+                                       }
+//printf(" ==> %.2lf\n\t", sigma);
+                               }
+
+                               sigma = StdDeviation(a, cnt, &mean);
+                               synthWave[swLen] = (uint32_t)(mean + 0.5);
+                               swAmplitude[swLen] = amplitude;
+                               swLen++;
+                               done2 = true;
+
+//printf("%d: ", swLen);
+                               for(uint32_t i=0; i<num; i++)
+                               {
+//printf("[%d->%d]", syncSave[i], syncPt[i]);
+                                       if (syncSave[i] != syncPt[i])
+                                       {
+                                               done2 = false;
+//                                             break;
+                                       }
+                               }
+//printf("\n");
+                       }
+
+                       sigma = StdDeviation(currentRow, num, &mean);
+                       synthWave[swLen] = mean;
+                       swAmplitude[swLen] = 1.0f;
+                       swLen++;
+               }
+       }
+
+       return swLen;
+}
+
+
+//
+// Attempt to find the sync point for the passed in stream #s.  If found, set
+// sync1 & sync2 to the spots where sync was found (typically, one or the other
+// will be zero) and return true, otherwise return false.
+//
+bool FindSync(uint32_t stream1, uint32_t stream2, uint32_t & sync1, uint32_t & sync2)
+{
+       sync1 = sync2 = 0;
+
+       // We *should* be able to synchronize within around 80 fluxes or so.  If not, then there's bigger problems.
+       for(uint32_t offset=0; offset<80; offset++)
+       {
+               uint32_t strmLen = Uint32LE(Global::stream[stream1]->dataLength);
+               bool found = true;
+
+               // How many bits should we consider as synchronized? All of them?
+               for(uint32_t i=1, i2=1; i<strmLen; i++, i2++)
+               {
+                       double time1 = (double)Global::stream[stream1]->data[i];
+                       double time2 = (double)Global::stream[stream2]->data[i2 + offset];
+
+                       while (Global::stream[stream1]->data[i] == 0xFF)
+                       {
+                               i++;
+                               time1 += (double)Global::stream[stream1]->data[i];
+                       }
+
+                       while (Global::stream[stream2]->data[i2] == 0xFF)
+                       {
+                               i2++;
+                               time2 += (double)Global::stream[stream2]->data[i2 + offset];
+                       }
+
+                       double mean = (time1 + time2) * 0.5;
+                       double sigma = sqrt(0.5 * (((time1 - mean) * (time1 - mean))
+                               + ((time2 - mean) * (time2 - mean))));
+
+                       if (sigma > 2.50)
+                       {
+                               // How many bits is enough to say we found it?
+/*
+N.B.: This (1,000) is fine for Apple Panic (which has shitty captures with junk in between sectors), but not for Championship Lode Runner which doesn't have any sync bytes for a loooooooooooong time
+*/
+                               if (i < 10000)
+                                       found = false;
+
+                               break;
+                       }
+               }
+
+               if (found)
+               {
+                       sync2 = offset;
+                       return true;
+               }
+       }
+
+       // Since we didn't find sync moving stream 2 forward, let's try stream 1
+       for(uint32_t offset=0; offset<80; offset++)
+       {
+               uint32_t strmLen = Uint32LE(Global::stream[stream2]->dataLength);
+               bool found = true;
+
+               // How many bits should we consider as synchronized? All of them?
+               for(uint32_t i=1, i2=1; i<strmLen; i++, i2++)
+               {
+                       double time1 = (double)Global::stream[stream2]->data[i];
+                       double time2 = (double)Global::stream[stream1]->data[i2 + offset];
+
+                       while (Global::stream[stream2]->data[i] == 0xFF)
+                       {
+                               i++;
+                               time1 += (double)Global::stream[stream2]->data[i];
+                       }
+
+                       while (Global::stream[stream1]->data[i2] == 0xFF)
+                       {
+                               i2++;
+                               time2 += (double)Global::stream[stream1]->data[i2 + offset];
+                       }
+
+                       double mean = (time1 + time2) * 0.5;
+                       double sigma = sqrt(0.5 * (((time1 - mean) * (time1 - mean))
+                               + ((time2 - mean) * (time2 - mean))));
+
+                       if (sigma > 2.50)
+                       {
+                               // How many bits is enough to say we found it?
+                               if (i < 10000)
+                                       found = false;
+
+                               break;
+                       }
+               }
+
+               if (found)
+               {
+                       sync1 = offset;
+                       return true;
+               }
+       }
+
+       return false;
+}
+
+
+void FindSyncForStreams(uint32_t * syncPt, uint32_t num)
+{
+//     uint32_t syncPt[10] = { 0 };
+       uint32_t base = 0;
+       syncPt[0] = 0;
+
+       for(uint32_t i=1; i<num; i++)
+       {
+               if (FindSync(sNum[base], sNum[i], syncPt[base], syncPt[i]) == true)
+               {
+                       // Check to see which stream has to move.  If it's not the current base, then we don't have to do anything but check the next one; otherwise, we have to shift everything done prior by the amount of the shift and set the new base to be the one that didn't move.
+                       if (syncPt[base] != 0)
+                       {
+                               for(uint32_t j=0; j<i; j++)
+                               {
+                                       if (j != base)
+                                               syncPt[j] += syncPt[base];
+                               }
+
+                               base = i;
+                       }
+               }
+               else
+               {
+                       // should we do this? or just set a flag that we couldn't sync this one?
+                       syncPt[i] = -1;
+//                     return;
+               }
+       }
+
+       // If there was no sync for any of the other tracks, signal this by counting the number of non-sync tracks and checking against the total # of tracks - 1.
+       uint32_t nonSync = 0;
+
+       for(uint32_t i=1; i<num; i++)
+       {
+               if (syncPt[i] == (uint32_t)-1)
+                       nonSync++;
+       }
+
+       // Signal that sync failed
+       if (nonSync == (num - 1))
+               syncPt[0] = -1;
+/*
+v v
+0 0 0 0 0  base = 0, i = 1
+
+0  1
+0, 10
+
+v    v
+0 10 0 0 0  base = 0, i = 2
+5 10 0 0 0
+
+0  2
+5, 0
+
+     v v
+5 15 0 0 0  base = 2, i = 3
+5 15 0 7 0
+
+2  3
+0, 7
+
+     v   v
+5 15 0 7 0  base = 2, i = 4
+5 15 8 7 0
+
+2  4
+8, 0
+
+13 23 8 15 0  base = 4
+
+       if (FindSync(sNum[0], sNum[1], syncPt[0], syncPt[1]) == false)
+       {
+               // give up, we couldn't sync stream 0 & 1...  :-/
+       }
+
+       // check to see which one had to move, and use the other to check against the rest...
+       uint32_t base = (syncPt[0] == 0 ? 0 : 1);
+
+       if (FindSync(sNum[base], sNum[2], syncPt[base], syncPt[2]) == false)
+       {
+               // give up, we couldn't sync stream 0 & 1...  :-/
+       }
+
+       // check again, to see which one moved and the other...
+       uint32_t base2 = (syncPt[base] == 0 ? base, 2);
+
+       // & so on...
+
+
+*/
+}
+
+
+void FindInitialSyncForStreams(uint32_t * sync, uint32_t num)
+{
+/*
+What we need to do is find the FF. or FF.. or FE..s, then find the first non-zero trailing byte after that to be our sync point.  If we don't, we run the risk of getting bad starts because some bitstreams might have some sync starts that start with the wrong number of 1 bits, and thus walking back will fail.
+*/
+       // Let's try aligning samples to each other by counting to a short stream
+       // of FF.(.)s...
+       uint64_t bitPat0 = 0;
+
+       for(uint32_t i=0; i<num; i++)
+       {
+               sync[i] = 0;
+               uint64_t bitPat = 0;
+               initSyncTime[i] = 0;
+
+               // We'll use a naïve window to scan for the bit patterns
+               for(int32_t j=0; j<Uint32LE(Global::stream[sNum[i]]->dataLength); j++)
+               {
+                       uint32_t timeToNext = Global::streamData[i][j];
+
+                       while (Global::streamData[i][j] == 0xFF)
+                       {
+                               j++;
+                               timeToNext += Global::streamData[i][j];
+                       }
+
+                       initSyncTime[i] += (double)timeToNext;
+
+                       if ((timeToNext >= 24) && (timeToNext <= 49))
+                               bitPat = (bitPat << 1) | 1;
+                       else if ((timeToNext >= 50) && (timeToNext <= 80))
+                               bitPat = (bitPat << 2) | 1;
+                       else if ((timeToNext >= 81) && (timeToNext <= 112))
+                               bitPat = (bitPat << 3) | 1;
+                       else
+                       {
+                               while (timeToNext > 32)
+                               {
+                                       bitPat <<= 1;
+                                       timeToNext -= 32;
+                               }
+                       }
+
+                       if (i == 0)
+                               bitPat0 = bitPat;
+
+                       // Search for first instance of 3 FF. or 3 FF.. in bitstream
+                       // Might need to look for FE.. as well
+                       //    0 1111 1111 0111 1111 1011 1111 1101
+                       // 0111 1111 1001 1111 1110 0111 1111 1001
+//                     if (((bitPat & 0x1FFFFFFF) == 0x0FF7FBFD)
+//                             || (bitPat & 0xFFFFFFFF) == 0x7F9FE7F9)
+                       // Need to see at least two regular bytes after as well:
+                       //    0 1111 1111 0111 1111 1011 1111 1101 xxxx xxx1 xxxx xxx1
+                       // 0111 1111 1001 1111 1110 0111 1111 1001 xxxx xxx1 xxxx xxx1
+                       if ((bitPat & 0x1FFFFFFF0101) == 0x0FF7FBFD0101)
+                       {
+                               if ((i != 0) && (bitPat != bitPat0))
+                                       continue;
+
+                               sync[i] = j - (j - 25 >= 0 ? 25 : 0);
+                               break;
+                       }
+                       else if ((bitPat & 0xFFFFFFFF0101) == 0x7F9FE7F90101)
+                       {
+                               if ((i != 0) && (bitPat != bitPat0))
+                                       continue;
+
+                               sync[i] = j - (j - 25 >= 0 ? 25 : 0);
+                               break;
+                       }
+               }
+       }
+}
+
+
+//
+// Walk through the streams backwards until we hit the zero point on one of them.  This assumes the sync point we found initially is a good one (it might not be!).
+//
+void BacktrackInitialSync(uint32_t * syncPt, uint32_t num)
+{
+//     uint32_t count = 0;
+       double a[10];
+//     uint32_t syncSave[10];
+
+       // Save the original sync points (do we need to?)
+//     for(uint32_t i=0; i<num; i++)
+//             syncSave[i] = syncPt[i];
+
+       uint32_t minSlip = (uint32_t)-1;
+
+       for(uint32_t i=0; i<num; i++)
+       {
+               if (syncPt[i] < minSlip)
+                       minSlip = syncPt[i];
+       }
+
+       while (minSlip > 0)
+       {
+               // Get the time for this step into a[]
+               for(uint32_t i=0; i<num; i++)
+               {
+                       // We scale the time by a factor of the measured RPM to 300 RPM, which should get us closer to a "normal" time for all streams
+                       a[i] = (double)Global::stream[sNum[i]]->data[syncPt[i]];// * ratio[i];
+
+                       while ((syncPt[i] > 0)
+                               && (Global::stream[sNum[i]]->data[syncPt[i] - 1] == 0xFF))
+                       {
+                               syncPt[i]--;
+                               a[i] += (double)Global::stream[sNum[i]]->data[syncPt[i]];// * ratio[i];
+                       }
+               }
+
+               double sigma = StdDeviation(a, num);
+//             count++;
+
+               if (sigma > SIGMA_THRESHOLD)
+               {
+                       printf("\n");
+
+                       for(uint32_t i=0; i<num; i++)
+//                             printf("<%6.2lf>", (double)Global::stream[sNum[i]]->data[syncPt[i]]);// * ratio[j]);
+                               printf("<%6.2lf>", a[i]);// * ratio[j]);
+
+                       printf(" --> %.2lf\n", sigma);
+
+                       uint32_t syncCount = 0;
+
+                       // Save sync origins for later analysis
+//                     for(uint32_t j=0; j<num; j++)
+//                             syncSave[j] = syncPt[j];
+
+                       // It may turn out that this is too large too...
+                       while (sigma > 3.30)//SIGMA_THRESHOLD)
+                       {
+                               // Deal with the problem.  The heuristic is find the largest value in the set, then advance the other streams by one step until they are "close" to the largest.  If the std. deviation is too large, try again; eventually it should be within good limits.
+                               uint32_t largestIdx = LargestIdx(a, num);
+
+                               for(uint32_t i=0; i<num; i++)
+                               {
+                                       if (i == largestIdx)
+                                       {
+                                               printf("  ~~~~  ");
+                                               continue;
+                                       }
+
+                                       int32_t walkBack = syncPt[i] - 1;
+                                       double ttn = (double)Global::stream[sNum[i]]->data[walkBack];
+
+                                       while ((walkBack > 0)
+                                               && (Global::stream[sNum[i]]->data[walkBack - 1] == 0xFF))
+                                       {
+                                               walkBack--;
+                                               ttn += (double)Global::stream[sNum[i]]->data[walkBack];// * ratio[i];
+                                       }
+
+                                       // If the difference between the highest and this is over 5, add the next time interval and let the sync counter, uh, slip (backwards!) :-)
+                                       if ((a[largestIdx] - a[i]) > 5.0)
+                                       {
+                                               syncPt[i] = walkBack;
+                                               a[i] += ttn;
+                                               printf(" %6.2lf ", ttn);
+                                       }
+                                       else
+                                               printf("        ");
+                               }
+
+                               printf("\n");
+
+                               for(uint32_t i=0; i<num; i++)
+                                       printf("<%6.2lf>", a[i]);
+
+                               sigma = StdDeviation(a, num);
+                               printf(" ==> %.2lf\n", sigma);
+
+                               syncCount++;
+
+                               if (syncCount > 20)
+                               {
+                                       // Back up the train
+                                       for(uint32_t i=0; i<num; i++)
+                                       {
+                                               syncPt[i] -= (syncPt[i] >= 40 ? 40 : 0);
+
+                                               if ((int32_t)syncPt[i] < 0)
+                                                       syncPt[i] = 0;
+                                       }
+
+                                       minSlip = 0;
+                                       printf("Could not synchronize streams...\n");
+                                       break;
+                               }
+                       }
+               }
+
+               // Point as the next time step and see where the minimum sync point is now...
+               for(uint32_t i=0; i<num; i++)
+               {
+                       syncPt[i]--;
+
+                       if (syncPt[i] < minSlip)
+                               minSlip = syncPt[i];
+               }
+       }
+}
+
+
+//
+// Walk through the streams backwards until we hit the zero point on one of them.  This assumes the sync point we found initially is a good one (it might not be!). [We've found that sometimes, the initial sync point is *really* bad.]
+//
+void BacktrackInitialSync2(uint32_t * syncPt, uint32_t num)
+{
+       double a[10];
+       uint32_t syncSave[10];
+       uint32_t minSlip = Smallest(syncPt, num);
+
+       while (minSlip > 0)
+       {
+               // Get the time for this step into a[]
+               for(uint32_t i=0; i<num; i++)
+               {
+                       // We scale the time by a factor of the measured RPM to 300 RPM, which should get us closer to a "normal" time for all streams
+                       a[i] = (double)Global::stream[sNum[i]]->data[syncPt[i]];// * ratio[i];
+
+                       while ((syncPt[i] > 0)
+                               && (Global::stream[sNum[i]]->data[syncPt[i] - 1] == 0xFF))
+                       {
+                               syncPt[i]--;
+                               a[i] += (double)Global::stream[sNum[i]]->data[syncPt[i]];// * ratio[i];
+                       }
+               }
+
+               double sigma = StdDeviation(a, num);
+
+               if (sigma > SIGMA_THRESHOLD)
+               {
+                       uint32_t syncCount = 0;
+
+                       // Save sync origins for later analysis
+                       memcpy(syncSave, syncPt, sizeof(syncSave));
+
+                       // It may turn out that this is too large too...
+                       while (sigma > SIGMA_THRESHOLD)
+                       {
+                               // Deal with the problem.  The heuristic is find the largest value in the set, then advance the other streams by one step until they are "close" to the largest.  If the std. deviation is too large, try again; eventually it should be within good limits.
+                               uint32_t largestIdx = LargestIdx(a, num);
+
+                               // We now pull all streams "forward" until they are within 7
+                               // underneath the largest or past it.
+                               for(uint32_t i=0; i<num; i++)
+                               {
+                                       if (i == largestIdx)
+                                               continue;
+
+                                       double ttn = 0;
+                                       int32_t walkback = syncPt[i];
+
+                                       while((a[largestIdx] - (a[i] + ttn)) > 7.0)
+                                       {
+                                               if (walkback <= 0)
+                                               {
+                                                       memcpy(syncPt, syncSave, sizeof(syncSave));
+                                                       printf("Synchronized as far back as possible...\n");
+                                                       return;
+                                               }
+
+                                               walkback--;
+                                               ttn += (double)Global::stream[sNum[i]]->data[walkback];// * ratio[i];
+
+                                               while ((walkback > 0)
+                                                       && (Global::stream[sNum[i]]->data[walkback - 1] == 0xFF))
+                                               {
+                                                       walkback--;
+                                                       ttn += (double)Global::stream[sNum[i]]->data[walkback];// * ratio[i];
+                                               }
+                                       }
+
+                                       syncPt[i] = walkback;
+                                       a[i] += ttn;
+                               }
+
+                               sigma = StdDeviation(a, num);
+
+                               syncCount++;
+
+                               if (syncCount > 20)
+                               {
+                                       // Back up the train
+                                       for(uint32_t i=0; i<num; i++)
+                                       {
+                                               syncPt[i] -= (syncPt[i] >= 40 ? 40 : 0);
+
+                                               if ((int32_t)syncPt[i] < 0)
+                                                       syncPt[i] = 0;
+                                       }
+
+                                       minSlip = 0;
+                                       printf("Could not synchronize streams...\n");
+                                       break;
+                               }
+                       }
+               }
+
+               // Point as the next time step and see where the minimum sync point is now...
+               for(uint32_t i=0; i<num; i++)
+               {
+                       syncPt[i]--;
+
+                       if (syncPt[i] < minSlip)
+                               minSlip = syncPt[i];
+               }
+       }
+}
+
+
+//
+// Walk through the streams backwards until we hit the zero point on one of them.  This assumes the sync point we found initially is a good one (it might not be!). [We've found that sometimes, the initial sync point is *really* bad.]
+//
+void BacktrackInitialSync3(uint32_t * sync, uint32_t num)
+{
+       double a[9];
+       uint32_t syncSave[9];
+
+       while (true)
+       {
+               uint32_t minSlip = Smallest(sync, num);
+
+               if (minSlip == 0)
+                       break;
+
+               // Save sync origins for later analysis if necessary
+               memcpy(syncSave, sync, sizeof(syncSave));
+
+               // Get the time for this step into a[]
+               StepBack(sync, a, num);
+               double sigma = StdDeviation(a, num);
+
+               if (sigma > SIGMA_THRESHOLD)
+               {
+                       uint32_t syncCount = 0;
+                       bool pulled;
+
+                       do
+                       {
+                               syncCount++;
+
+                               if (syncCount > 20)
+                               {
+                                       // Back up the train
+                                       for(uint32_t i=0; i<num; i++)
+                                       {
+                                               sync[i] -= (sync[i] >= 40 ? 40 : 0);
+
+                                               if ((int32_t)sync[i] < 0)
+                                                       sync[i] = 0;
+                                       }
+
+                                       printf("Could not synchronize streams...\n");
+                                       return;
+                               }
+
+                               // Deal with the problem.  The heuristic is find the largest value in the set, then advance the other streams by one step until they are "close" to the largest.  If the std. deviation is too large, try again; eventually it should be within good limits.
+                               uint32_t largestIdx = LargestIdx(a, num);
+                               pulled = false;
+
+                               // We now pull all streams "forward" until they are within 7
+                               // underneath the largest or past it.
+                               for(uint32_t i=0; i<num; i++)
+                               {
+                                       if (i == largestIdx)
+                                               continue;
+
+                                       double ttn = 0;
+                                       uint32_t walkback = sync[i];
+
+                                       while((a[largestIdx] - (a[i] + ttn)) > 7.0)
+                                       {
+                                               pulled = true;
+
+                                               if ((int32_t)walkback <= 0)
+                                               {
+                                                       memcpy(sync, syncSave, sizeof(syncSave));
+                                                       printf("Synchronized as far back as possible...\n");
+                                                       return;
+                                               }
+
+                                               StepAndAddBack(walkback, ttn, i);
+                                       }
+
+                                       sync[i] = walkback;
+                                       a[i] += ttn;
+                               }
+
+                               // Calculate the standard deviation at this new point
+                               sigma = StdDeviation(a, num);
+
+                               // Heuristic: see if we're stuck with a bad sigma and can't pull any more forward; if so, pull forward one step and see if that gets us any traction...
+                               if ((sigma > SIGMA_THRESHOLD) && !pulled)
+                               {
+                                       for(uint32_t i=0; i<num; i++)
+                                               StepAndAddBack(sync[i], a[i], i);
+
+                                       sigma = StdDeviation(a, num);//, &mean);
+                                       pulled = true;
+                               }
+                       }
+                       while ((sigma > SIGMA_THRESHOLD) && pulled);
+               }
+       }
+}
+
+
+void BacktrackInitialSync4(uint32_t * sync, uint32_t num)
+{
+       double a[9], a2[9];
+       uint32_t syncSave[9];
+
+       while (true)
+       {
+               uint32_t minSlip = Smallest(sync, num);
+
+               if (minSlip == 0)
+                       break;
+
+               // Save sync origins for later analysis if necessary
+               memcpy(syncSave, sync, sizeof(syncSave));
+
+               // Get the time for this step into a[]
+               StepBack(sync, a, num);
+               double sigma = StdDeviation(a, num);
+
+               if (sigma > SIGMA_THRESHOLD)
+               {
+printf("\n");
+for(uint32_t i=0; i<num; i++) { printf("<%6.2lf>", a[i]); }
+printf(" --> %.2lf\n", sigma);
+                       // Let's see if we can re-sync through this rough patch
+                       int result = Resync(sync, a, num, -1);
+
+                       // Well, we failed to find synchronization...  :-(
+                       if (result == -1)
+                       {
+                               memcpy(sync, syncSave, sizeof(syncSave));
+                               return;
+                       }
+
+                       // OK, we have a good result, but what kind (1=end, 0=sync OK)?
+                       if (result == 0)
+                               StepBack(sync, a2, num);
+                       else if (result == 1)
+                       {
+for(uint32_t j=0; j<num; j++) { printf("{%d} ", sync[j]); }
+printf("\n");
+                               memcpy(sync, syncSave, sizeof(syncSave));
+for(uint32_t j=0; j<num; j++) { printf("<%d> ", sync[j]); }
+printf("\n");
+                               StepBack(sync, a2, num);
+                               return;
+                       }
+               }
+       }
+}
+
+
+void StepBackUntilBad(uint32_t * sync, double * a, uint32_t num)
+{
+       while (true)
+       {
+               // See where the minimum sync point is now...
+               uint32_t minSlip = Smallest(sync, num);
+
+               if (minSlip == 0)
+                       break;
+
+               // Get the time for this step into a[]
+               StepBack(sync, a, num);
+               double sigma = StdDeviation(a, num);
+
+               if (sigma > SIGMA_THRESHOLD)
+               {
+                       printf("\n");
+
+                       for(uint32_t i=0; i<num; i++)
+                               printf("<%6.2lf>", a[i]);
+
+                       printf(" --> %.2lf\n", sigma);
+                       return;
+               }
+       }
+
+       printf("---------------------------------------------------\nAT START\n\n");
+}
+
+
+bool StepBackThruBad(uint32_t * sync, double * a, uint32_t num)
+{
+       // Deal with the problem.  The heuristic is find the largest value in the set, then advance the other streams by one step until they are "close" to the largest.  If the std. deviation is too large, try again; eventually it should be within good limits.
+       uint32_t largestIdx = LargestIdx(a, num);
+
+/*
+New heuristic to try here: advance each stream until it comes within 7 on the bottom end or passes it altogether; check the sigma then.
+
+2nd heuristic: attempt to pull the next 'num' time all at once and *add* it to the current step, check the sigma to see if it's in tolerance (*and* check the lookahead).
+*/
+       for(uint32_t i=0; i<num; i++)
+       {
+               if (i == largestIdx)
+               {
+                       printf("  ~~~~  ");
+                       continue;
+               }
+
+               // heuristic 1
+               bool seen = false;
+               double ttn = 0;
+               uint32_t walkback = sync[i];
+
+               // If the difference between the highest and this is over 7, add the next time interval and let the sync counter, uh, slip (backwards!) :-)
+               while ((a[largestIdx] - (a[i] + ttn)) > 7.0)
+               {
+                       seen = true;
+                       StepAndAddBack(walkback, ttn, i);
+               }
+
+               sync[i] = walkback;
+               a[i] += ttn;
+
+               if (seen)
+                       printf(" %6.2lf ", ttn);
+               else
+                       printf("        ");
+       }
+
+       printf("\n");
+
+       for(uint32_t i=0; i<num; i++)
+               printf("<%6.2lf>", a[i]);
+
+       double sigma = StdDeviation(a, num);
+       printf(" ==> %.2lf%s", sigma, (sigma <= SIGMA_THRESHOLD ? " (OK)" : ""));
+
+double lookahead[9];
+for(uint32_t i=0; i<num; i++)
+       lookahead[i] = (double)Global::streamData[i][sync[i] - 1] * ratio[i];
+printf(" (lookahead=%.2lf, %d)\n", StdDeviation(lookahead, num), Lookahead(sync, num, -1));
+for(uint32_t j=0; j<num; j++) { printf("{%d}%s", sync[j], (j < num - 1 ? "-" : "")); }
+printf("\n");
+
+       if (sigma < SIGMA_THRESHOLD)
+       {
+               // If we're out of the woods, make sure to step to the next step...
+               double b[9];
+               StepBack(sync, b, num);
+               return false;
+       }
+
+       return true;
+}
+
+
+void StepBack(uint32_t * sync, double * a, uint32_t num)
+{
+       for(uint32_t i=0; i<num; i++)
+       {
+               int32_t walkback = sync[i] - 1;
+               a[i] = (double)Global::streamData[i][walkback] * ratio[i];
+
+               while ((walkback > 0)
+                       && (Global::streamData[i][walkback - 1] == 0xFF))
+               {
+                       walkback--;
+                       a[i] += (double)Global::streamData[i][walkback] * ratio[i];
+               }
+
+               sync[i] = walkback;
+       }
+}
+
+
+void StepAndAddBack(uint32_t * sync, double * a, uint32_t num)
+{
+       for(uint32_t i=0; i<num; i++)
+       {
+               int32_t walkback = sync[i] - 1;
+               a[i] += (double)Global::streamData[i][walkback] * ratio[i];
+
+               while ((walkback > 0)
+                       && (Global::streamData[i][walkback - 1] == 0xFF))
+               {
+                       walkback--;
+                       a[i] += (double)Global::streamData[i][walkback] * ratio[i];
+               }
+
+               sync[i] = walkback;
+       }
+}
+
+
+void StepAndAddBack(uint32_t & loc, double & a, uint32_t i)
+{
+       int32_t walkback = loc - 1;
+       a += (double)Global::streamData[i][walkback] * ratio[i];
+
+       while ((walkback > 0)
+               && (Global::streamData[i][walkback - 1] == 0xFF))
+       {
+               walkback--;
+               a += (double)Global::streamData[i][walkback] * ratio[i];
+       }
+
+       loc = (uint32_t)walkback;
+}
+
+
+//
+// Move every stream forward by one step
+//
+void StepForward(uint32_t * sync, double * a, uint32_t num)
+{
+       for(uint32_t i=0; i<num; i++)
+       {
+               uint32_t walkahead = sync[i] + 1;
+               a[i] = (double)Global::streamData[i][walkahead] * ratio[i];
+
+               while ((walkahead < Global::streamLen[i])
+                       && (Global::streamData[i][walkahead] == 0xFF))
+               {
+                       walkahead++;
+                       a[i] += (double)Global::streamData[i][walkahead] * ratio[i];
+               }
+
+               sync[i] = walkahead;
+       }
+}
+
+
+//
+// Move every stream forward by one step
+//
+void StepAndAddForward(uint32_t * sync, double * a, uint32_t num)
+{
+       for(uint32_t i=0; i<num; i++)
+       {
+               uint32_t walkahead = sync[i] + 1;
+               a[i] += (double)Global::streamData[i][walkahead] * ratio[i];
+
+               while ((walkahead < Global::streamLen[i])
+                       && (Global::streamData[i][walkahead] == 0xFF))
+               {
+                       walkahead++;
+                       a[i] += (double)Global::streamData[i][walkahead] * ratio[i];
+               }
+
+               sync[i] = walkahead;
+       }
+}
+
+
+//
+// Move just *this* stream forward by one step
+//
+void StepAndAddForward(uint32_t & loc, double & a, uint32_t i)
+{
+       loc++;
+       a += (double)Global::streamData[i][loc] * ratio[i];
+
+       while ((loc < Global::streamLen[i])
+               && (Global::streamData[i][loc] == 0xFF))
+       {
+               loc++;
+               a += (double)Global::streamData[i][loc] * ratio[i];
+       }
+}
+
+
+//
+// Return the number of times with good correlation in the specified direction
+// (1 for forward, -1 for backwards)
+//
+uint32_t Lookahead(uint32_t * syncPt, uint32_t num, int32_t dir /*= 1*/)
+{
+       uint32_t tSync[10];
+       double a[10];
+       uint32_t count = 0;
+
+       // Use temporary sync array instead of the one passed in
+       memcpy(tSync, syncPt, sizeof(tSync));
+
+       if (dir == -1)
+       {
+               uint32_t smallestIdx = SmallestIdx(tSync, num);
+
+               while (tSync[smallestIdx] > 0)
+               {
+                       StepBack(tSync, a, num);
+                       double sigma = StdDeviation(a, num);
+
+                       if (sigma > SIGMA_THRESHOLD)
+                               break;
+
+                       count++;
+                       smallestIdx = SmallestIdx(tSync, num);
+               }
+       }
+       else
+       {
+               uint32_t largestIdx = LargestIdx(tSync, num);
+
+               while (tSync[largestIdx] < Global::streamLen[largestIdx])
+               {
+                       StepForward(tSync, a, num);
+                       double sigma = StdDeviation(a, num);
+
+                       if (sigma > SIGMA_THRESHOLD)
+                               break;
+
+                       count++;
+                       largestIdx = LargestIdx(tSync, num);
+               }
+       }
+
+       return count;
+}
+
+
+//
+// Attempt to resynchronize the current streams
+// N.B.: When we get here, we're already at the point *after* where it blew up
+//       the sigma (the times for that step are passed-in in "a")
+//
+// Returns -1 on failure, 0 is sync was successful, or 1 if reached end of
+// stream before finding sync
+//
+int Resync(uint32_t * sync, double * a, uint32_t num, int32_t dir/*= 1*/)
+{
+       uint32_t syncCount = 0;
+       bool pulled;
+       double sigma = 0;
+
+for(uint32_t j=0; j<num; j++) { printf("{%d} ", sync[j]); }
+printf("\n");
+       do
+       {
+               syncCount++;
+
+               if (syncCount > 20)
+               {
+                       // Back up the train
+                       printf("Could not synchronize streams...\n");
+                       return -1;
+               }
+
+               // Deal with the problem.  The heuristic is find the largest value in the set, then advance the other streams by one step until they are "close" to the largest.  If the std. deviation is too large, try again; eventually it should be within good limits.
+               uint32_t largestIdx = LargestIdx(a, num);
+               pulled = false;
+
+               // We now pull all streams "forward" until they are within 7
+               // underneath the largest or past it.
+               for(uint32_t i=0; i<num; i++)
+               {
+                       if (i == largestIdx)
+                       {
+                               printf("  ~~~~  ");
+                               continue;
+                       }
+
+                       double ttn = 0;
+                       uint32_t walkback = sync[i];
+
+                       while ((a[largestIdx] - (a[i] + ttn)) > 7.0)
+                       {
+                               pulled = true;
+
+                               if (((dir == 1) && (walkback >= Global::streamLen[i]))
+                                       || ((dir == -1) && ((int32_t)walkback <= 0)))
+                               {
+//                                     memcpy(sync, syncSave, sizeof(syncSave));
+                                       printf("\nSynchronized as far back as possible...\n");
+for(uint32_t j=0; j<num; j++) { printf("{%d} ", sync[j]); }
+printf("\n");
+                                       return 1;
+                               }
+
+                               if (dir == 1)
+                                       StepAndAddForward(walkback, ttn, i);
+                               else
+                                       StepAndAddBack(walkback, ttn, i);
+                       }
+
+                       sync[i] = walkback;
+                       a[i] += ttn;
+
+                       if (pulled)
+                               printf(" %6.2lf ", ttn);
+                       else
+                               printf("        ");
+               }
+
+               printf("\n");
+
+               for(uint32_t i=0; i<num; i++)
+                       printf("<%6.2lf>", a[i]);
+
+               // Calculate the standard deviation at this new point
+               sigma = StdDeviation(a, num);
+printf(" ==> %.2lf%s", sigma, (sigma <= SIGMA_THRESHOLD ? " (OK)" : (!pulled ? "(STEP)" : "")));
+
+double lookahead[9];
+uint32_t minSyncIdx = SmallestIdx(sync, num);
+if (sync[minSyncIdx] > 0 && dir == -1)
+{
+for(uint32_t i=0; i<num; i++)
+{      lookahead[i] = (double)Global::streamData[i][sync[i] + dir] * ratio[i]; }
+printf(" (lookahead=%.2lf, %d)\n", StdDeviation(lookahead, num), Lookahead(sync, num, dir));
+}
+               // Heuristic: see if we're stuck with a bad sigma and can't pull any more forward; if so, pull forward one step and see if that gets us any traction...
+               if ((sigma > SIGMA_THRESHOLD) && !pulled)
+               {
+                       if (dir == 1)
+                               StepAndAddForward(sync, a, num);
+                       else
+                               StepAndAddBack(sync, a, num);
+
+                       sigma = StdDeviation(a, num);//, &mean);
+                       pulled = true;
+               }
+       }
+       while ((sigma > SIGMA_THRESHOLD) && pulled);
+
+//     double a2[9];
+//     StepBack(sync, a2, num);
+
+       return 0;
+}
+
+#endif
+
+
+//
+// Compare two arrays to see if they are equal
+//
+bool Equal(uint32_t * a1, uint32_t * a2, uint32_t num)
+{
+       for(uint32_t i=0; i<num; i++)
+       {
+               if (a1[i] != a2[i])
+                       return false;
+       }
+
+       return true;
+}
+
+
+uint32_t LookaheadWave(uint32_t * passedInSync, uint32_t num, int8_t dir = 1);
+uint32_t LookaheadWave(uint32_t * passedInSync, uint32_t num, int8_t dir/*= 1*/)
+{
+       uint32_t sync[6];
+       uint32_t count = 0;
+       memcpy(sync, passedInSync, sizeof(sync));
+
+       while (true)
+       {
+               if (StdDeviationWave(sync, num) > 2.50)
+                       break;
+
+               for(uint32_t i=0; i<num; i++)
+               {
+                       if (((dir == 1) && (sync[i] >= Global::waveLen[sNum[i]]))
+                               || ((dir == -1) && (sync[i] == 0)))
+                               return count;
+
+                       sync[i] += dir;
+               }
+
+               count++;
+       }
+
+       return count;
+}
+
+
+uint32_t FindSyncBetweenFirstTwo(uint32_t * sync)
+{
+       uint32_t bestSync[2], bestLA = 0, syncSave = sync[0];
+
+       // Move the first stream first...
+       for(uint32_t i=0; i<200; i++)
+       {
+               uint32_t la = LookaheadWave(sync, 2);
+
+               // See if the sync we've found is the best so far...
+               if (la > bestLA)
+               {
+                       bestLA = la;
+                       memcpy(bestSync, sync, sizeof(bestSync));
+               }
+
+               sync[0]++;
+       }
+
+       // Otherwise, reset the first stream and move the 2nd
+       sync[0] = syncSave;
+
+       for(uint32_t i=0; i<200; i++)
+       {
+               // We can bump this first since we already checked the [0][0] case above
+               sync[1]++;
+               uint32_t la = LookaheadWave(sync, 2);
+
+               // See if the sync we've found is the best so far...
+               if (la > bestLA)
+               {
+                       bestLA = la;
+                       memcpy(bestSync, sync, sizeof(bestSync));
+               }
+       }
+
+       // Set sync to the best we found & return the best lookahead count
+       memcpy(sync, bestSync, sizeof(bestSync));
+
+       return bestLA;
+}
+
+
+void FindInitialSyncForStreams2(uint32_t * sync, uint32_t num)
+{
+       bool lookAt[6] = { true, true, false, false, false, false };
+
+//     while (FindSyncBetweenFirstTwo(sync) == false)
+       while (FindSyncBetweenFirstTwo(sync) < 1000)
+       {
+               for(uint32_t i=0; i<num; i++)
+               {
+                       sync[i] += 200;
+
+                       if (sync[i] >= Global::waveLen[sNum[i]])
+                       {
+                               printf("Could not find initial sync!!\n");
+                               return;// -1;
+                       }
+               }
+       }
+
+       uint32_t lookahead = LookaheadWave(sync, 2);
+
+       if (lookAt[0])
+               printf("Found sync for streams 1 & 2 at %d and %d (la=%d)\n", sync[0], sync[1], lookahead);
+
+       // Add in the others, one at a time and try to synchronize them
+       uint32_t bestSync[6];
+
+       for(uint32_t i=2; i<num; i++)
+       {
+               lookAt[i] = true;
+               uint32_t bestLA = 0;
+
+               for(uint32_t j=0; j<200; j++)
+               {
+                       uint32_t syncSave = sync[i];
+
+                       // And check again for a match
+                       for(uint32_t k=0; k<200; k++)
+                       {
+                               uint32_t la = LookaheadWave(sync, i + 1);
+
+                               if (la > bestLA)
+                               {
+                                       bestLA = la;
+                                       memcpy(bestSync, sync, sizeof(bestSync));
+                               }
+
+                               sync[i]++;
+                       }
+
+                       sync[i] = syncSave;
+
+                       // Kick synchronized streams forward to check the rest...
+                       for(uint32_t k=0; k<i; k++)
+                               sync[k]++;
+               }
+
+               memcpy(sync, bestSync, sizeof(bestSync));
+       }
+
+       for(uint32_t i=0; i<num; i++)
+               printf("Sync for stream %d: %d (%s)\n", i, sync[i], (lookAt[i] ? "yes" : "no"));
+       printf("Lookahead: %d\n", LookaheadWave(sync, num));
+}
+
+
+#if 1
+uint32_t Synthesize2(uint32_t * sync, uint32_t num, uint32_t * synthWave, float * swAmplitude)
+{
+       uint32_t swLen = 0;
+       uint32_t syncPt[7], syncSave[7];
+       double a[7], b[7], currentRow[7];
+       Global::bloops = 0;
+
+       memcpy(syncPt, sync, sizeof(syncPt));
+
+       while (true)
+       {
+               for(uint32_t i=0; i<num; i++)
+               {
+                       if (syncPt[i] >= Global::streamLen[i])
+                               return swLen;
+               }
+
+               // Save these *before* we step forward
+               memcpy(syncSave, syncPt, sizeof(syncSave));
+//             StepForward(syncPt, a, num);
+               for(uint32_t i=0; i<num; i++)
+               {
+                       a[i] = (double)Global::wave[sNum[i]][syncPt[i]];
+                       syncPt[i]++;
+               }
+
+               double mean;
+               double sigma = StdDeviation(a, num, &mean);
+
+               if (sigma <= SIGMA_THRESHOLD)
+               {
+                       synthWave[swLen] = (uint32_t)(mean + 0.5);
+                       swAmplitude[swLen] = 1.0f;
+                       swLen++;
+               }
+               else
+               {
+                       Global::bloops++;
+                       // The basic idea is to find the extent of this anomalous region and then use what's there as an amplitude by summing the signals where they correspond.
+                       uint32_t syncSteps = 0;
+                       uint32_t lookahead = LookaheadWave(syncPt, num);
+
+                       // Basically we move forward thru the area until either 1) the sigma is OK, or 2) we've pulled everything as far as it can go and thus this becomes our new local start. 3) will go in at some point which is, do a lookahead and see what the sigma looks like; if it's good and the current one is stinko, (not *too* stinko) then we've found a new local start point, otherwise keep going.
+/*
+Note that 3) works OK to get out of sticky situations, but sometimes the signals are fairly noisy and you will end up in situations where the lookahead is zero and the next sigma isn't great (& the current isn't any good either), but using that as the new local start is OK and will permit walking forward/backward through the stream.  Some of the time you will find the average of the current sigma and the following will be below the threshold with a good lookahead value (10, 100, 1000), this is also a good time to set the new local start.
+*/
+#ifdef NOISY
+printf("a: ");
+for(uint32_t i=0; i<num; i++)
+       printf("[%.2lf]", a[i]);
+//printf(" => %.2lf {drift=%.2lf, la=%d}\n", sigma, driftSigma, lookahead);
+printf(" => %.2lf {la=%d}\n", sigma, lookahead);
+
+for(uint32_t j=0; j<num; j++) { printf("{%d}%s", syncPt[j], (j < num - 1 ? "-" : "")); }
+printf("\n");//*/
+#endif
+                       bool keepWorking = true;
+
+                       do
+                       {
+                               syncSteps++;
+
+                               // If we've been in this loop too long, something's very wrong
+                               if (syncSteps > 20)
+                                       return swLen;
+
+                               // Pull the lesser streams forward to catch up to the largest
+                               uint32_t largestIdx = LargestIndex(a, num);
+                               bool pulled = false;
+
+                               for(uint32_t i=0; i<num; i++)
+                               {
+                                       if (i == largestIdx)
+#ifdef NOISY
+                                       {
+                                               printf("  ~~~~  ");
+#endif
+                                               continue;
+#ifdef NOISY
+                                       }
+#endif
+//                                     if ((a[largestIdx] - a[i]) > 7.0)
+                                       if ((a[largestIdx] - a[i]) > 9.0)
+                                       {
+                                               pulled = true;
+                                               a[i] += (double)Global::wave[sNum[i]][syncPt[i]];
+#ifdef NOISY
+                                               printf(" %6d ", Global::wave[sNum[i]][syncPt[i]]);
+#endif
+                                               syncPt[i]++;
+                                       }
+#ifdef NOISY
+                                       else
+                                               printf("        ");
+#endif
+                                       // See if we've run out of stream to synthesize...
+                                       if (syncPt[i] >= Global::waveLen[sNum[i]])
+                                               return swLen;
+                               }
+
+#ifdef NOISY
+                               printf("\n");
+
+                               for(uint32_t i=0; i<num; i++)
+                                       printf("<%6.2lf>", a[i]);
+#endif
+                               // Calculate the standard deviation at this new point
+                               sigma = StdDeviation(a, num);//, &mean);
+
+                               // Calculate the following sigma & lookahead too
+                               for(uint32_t i=0; i<num; i++)
+                                       b[i] = (double)Global::wave[sNum[i]][syncPt[i]];
+
+                               double nextSigma = StdDeviation(b, num);
+                               lookahead = LookaheadWave(syncPt, num);
+#ifdef NOISY
+                               printf(" ==> %.2lf%s", sigma, (sigma <= SIGMA_THRESHOLD ? " (OK)" : (!pulled ? "(STEP)" : "")));
+                               printf(" (lookahead=%.2lf, %d)\n", nextSigma, lookahead);
+
+for(uint32_t j=0; j<num; j++) { printf("{%d}%s", syncPt[j], (j < num - 1 ? "-" : "")); }
+printf("\n");//*/
+#endif
+                               // A handful of heuristics.  If the sigma is OK, we're done
+                               if (sigma < 2.5)
+                                       keepWorking = false;
+
+                               // If we couldn't pull any streams forward for some reason, punt
+                               if (!pulled)
+                                       keepWorking = false;
+
+                               // If the average of the current & next sigmas is OK, go ahead
+                               if (((sigma + nextSigma) / 2.0) < 2.5)
+                                       keepWorking = false;
+
+                               // If the next sigma is OK and the lookahead too, move on
+                               if ((nextSigma < 2.5) && (lookahead > 10))
+                                       keepWorking = false;
+                       }
+                       while (keepWorking);
+
+                       // Now, we've re-established sync, now fill the appropriate spots
+
+/*
+So the algorithm to do this proppaly is like so:
+
+Step 1: Find the smallest step forward through the section; set amplitude to 0.2.
+Step 2: Loop thru the other streams and see if they correspond.  If so, advance their stream start & add 0.2 to the amplitude for each one seen.
+Step 3: Add the mean value of the corresponding values to the synthesized waveform + wave amplitude
+Step 4: If all of the stream starts are at the end of the section, we are done.
+[maybe.  how do you handle the case where you have streams that look like so:
+
+200
+150 50
+150 50
+175 25
+200
+
+.......................................|
+.............................|.........|
+.............................|.........|
+..................................|....|
+.......................................|
+
+this will fail to add in the correct amount for the times that had no part in the anomaly.  so to fix this, maybe have a baseline value that bumps upward to show where the "cursor" (so to speak) is, so at the end we can subtract the mean that we got above from this baseline to get the remaining time to synthesize, like so:
+
+synthWave[swLen] = (uint32_t)((mean - baseline) + 0.5)
+swAmplitude[swLen] = amplitude;
+
+no need for that.  the times that step directly to the end can safely be ignored.
+]
+
+150 -> 150 (ignores 175)
+150 goes in, ampl. .4, we now have:
+
+200
+50
+50
+175 25
+200
+
+only one is left that we can grab:
+
+175
+
+last pulse was at 150 (40%), so we need to subtract that out
+
+-> 25
+
+so maybe we'd do like so:
+-1) create a list containing the start values for the start of the anomalous section and replace them as the counters advance.
+0) are streams at the end? if so, stuff in the final value to the synthesized wave & stop, otherwise:
+1) find the smallest in the current row and use that as a basis.
+2) find streams that correlate, if any
+3) advance the streams that correlate & subtract out the minimum from the other rows
+4) go to 0)
+
+200
+150 50
+150 50
+175 25
+200
+
+smallest is 150: pick 150 -> picks up 150
+advance the 150 rows & subtract 150 from the rest:
+
+50
+50
+50
+25 25
+50
+
+pick smallest: 25 -> picks up nothing
+advance the 25 & subtract it from the rest:
+
+25
+25
+25
+25
+25
+
+We've reached the end of the section, add the final amount
+
+--------------------------------------------------------------------------------
+syncSave before: [2->4][2->6][2->4][2->6][2->6]
+syncSave after: [3->4][3->6][3->4][3->6][3->6]
+
+currentRow: [120.89][49.97][46.98][49.98][48.98] => 28.78
+
+2: [3->4][3->6][3->4][3->6][3->6]
+
+a[0]=46.98: [120.89] ==> 36.95
+        [49.97]{17.00} ==> 1.50
+        <106.00>[49.97][49.98]{28.00} ==> 1.41
+        [49.97][49.98][48.98]{26.00} ==> 1.22
+
+3: [3->4][4->6][4->4][4->6][4->6]
+
+a[0]=17.00: [73.91] ==> 28.45
+        <56.00>[28.00]{45.00} ==> 5.50
+        [28.00][26.00]{47.00} ==> 4.78
+
+4: [3->4][5->6][4->4][5->6][5->6]
+
+a[0]=45.00: [56.91] ==> 5.95
+        [56.00]{32.00} ==> 5.50
+        <32.00>[56.00][47.00]{32.00} ==> 4.78
+
+5: [3->4][6->6][4->4][6->6][6->6]
+
+a[0]=11.91: <32.00>
+
+6: [4->4][6->6][4->4][6->6][6->6]
+
+ 2->4    2->6    2->4    2->6    2->6
+[120.89][ 49.97][ 46.98][ 49.98][ 48.98] => 28.78
+( 73.91)  17.00  106.00   28.00   26.00
+( 56.91)  56.00           45.00   47.00
+  32.00   32.00           32.00   32.00
+
+*/
+#ifdef NOISY
+/*printf("syncSave before: ");
+for(uint32_t i=0; i<num; i++)
+       printf("[%d->%d]", syncSave[i], syncPt[i]);
+printf("\n");//*/
+
+for(uint32_t i=0; i<num; i++)
+{
+       printf("Sync %d: %d -> %d (", sNum[i], syncSave[i], syncPt[i]);
+       for(uint32_t j=syncSave[i]; j<=syncPt[i]; j++)
+               printf("%d%s", Global::wave[sNum[i]][j], (j == syncPt[i] ? "" : ", "));
+       printf(")\n");
+}
+#endif
+                       // Collect the current row
+                       for(uint32_t i=0; i<num; i++)
+                       {
+                               currentRow[i] = (double)Global::wave[sNum[i]][syncSave[i]];
+                               syncSave[i]++;
+                       }
+
+/*printf("syncSave after: ");
+for(uint32_t i=0; i<num; i++)
+       printf("[%d->%d]", syncSave[i], syncPt[i]);
+printf("\n");
+printf("currentRow: ");
+for(uint32_t i=0; i<num; i++)
+       printf("[%.2lf]", currentRow[i]);
+printf(" => %.2lf\n", StdDeviation(currentRow, num));//*/
+
+//printf("%d: ", swLen);
+
+                       float ampStep = 1.0f / (float)num;
+
+                       while (true)
+                       {
+                               if (Equal(syncSave, syncPt, num))
+                                       break;
+
+                               float amplitude = ampStep;
+                               uint32_t smallestIdx = SmallestIndex(currentRow, num);
+                               uint32_t cnt = 1;
+                               a[0] = currentRow[smallestIdx];
+//printf("a[0]=%.2lf: ", a[0]);
+
+                               for(uint32_t i=0; i<num; i++)
+                               {
+                                       // Make sure we haven't gone beyond the end of any of the streams we're looking at
+                                       if (syncSave[i] >= Global::streamLen[i])
+                                               return swLen;
+
+                                       if (i == smallestIdx)
+                                       {
+                                               // We always pick up the smallest in the current set, since that's our basis
+                                               currentRow[i] = (double)Global::wave[sNum[i]][syncSave[i]];
+                                               syncSave[i]++;
+//printf("<%.2lf>", currentRow[i]);
+                                               continue;
+                                       }
+
+                                       // Save the current row & subtract out the smallest as a basis
+                                       double crSave = currentRow[i];
+                                       currentRow[i] -= a[0];
+
+                                       // Don't bother with stuff that's out of range (@ current sync point!)  :-P
+                                       if (syncSave[i] == syncPt[i])
+                                               continue;
+
+                                       // Try to find correlates
+                                       a[cnt] = crSave;
+                                       cnt++;
+                                       sigma = StdDeviation(a, cnt);
+//for(uint32_t j=1; j<cnt; j++)
+//     printf("[%.2lf]", a[j]);
+
+//relaxed sigma...
+                                       if (sigma <= 5.5)//SIGMA_THRESHOLD)
+                                       {
+                                               // If the sigma is in range for this item, pick it up
+                                               currentRow[i] = (double)Global::wave[sNum[i]][syncSave[i]];
+                                               syncSave[i]++;
+
+//printf("{%.2lf}", currentRow[i]);
+                                               amplitude += ampStep;
+                                       }
+                                       else
+                                       {
+                                               // Otherwise reject the last item; it's too far out
+                                               cnt--;
+                                       }
+//printf(" ==> %.2lf\n\t", sigma);
+                               }
+
+                               // Get the average of the items picked up and add it to the wave
+                               sigma = StdDeviation(a, cnt, &mean);
+                               synthWave[swLen] = (uint32_t)(mean + 0.5);
+                               swAmplitude[swLen] = amplitude;
+                               swLen++;
+                       }
+
+                       sigma = StdDeviation(currentRow, num, &mean);
+                       synthWave[swLen] = mean;
+                       swAmplitude[swLen] = 1.0f;
+                       swLen++;
+               }
+       }
+
+       return swLen;
+}
+#endif
+
+
+bool ResyncWave(uint32_t * sync, uint32_t num, int8_t dir = 1);
+bool ResyncWave(uint32_t * sync, uint32_t num, int8_t dir/*= 1*/)
+{
+       double a[6];
+
+       for(uint32_t i=0; i<num; i++)
+       {
+               a[i] = (double)Global::wave[sNum[i]][sync[i]];
+               sync[i] += dir;
+       }
+
+#ifdef NOISY
+       for(uint32_t i=0; i<num; i++)
+               printf("<%4d>", (uint32_t)a[i]);
+
+       printf(" {la: %d}\n", LookaheadWave(sync, num, dir));
+#endif
+
+       uint32_t syncCount = 0;
+       bool keepGoing = true;
+
+       do
+       {
+               if (syncCount > 42)
+               {
+                       printf("Could not synchronize streams...\n");
+                       return false;
+               }
+
+               for(uint32_t i=0; i<num; i++)
+               {
+                       if (((dir == 1) && (sync[i] >= Global::waveLen[sNum[i]]))
+                               || ((dir == -1) && (sync[i] == 0)))
+                       {
+                               printf("End of stream...\n");
+                               return true;
+                       }
+               }
+
+               // Deal with the problem.  The heuristic is find the largest value in the set, then advance the other streams by one step until they are "close" to the largest.  If the std. deviation is too large, try again; eventually it should be within good limits.
+               uint32_t largestIdx = LargestIndex(a, num);
+               bool stepped = false;
+
+               for(uint32_t i=0; i<num; i++)
+               {
+                       if (i == largestIdx)
+#ifdef NOISY
+                       {
+                               printf(" ~~~~ ");
+#endif
+                               continue;
+#ifdef NOISY
+                       }
+#endif
+
+                       // If the difference between the highest and this is over 7, add the next time interval and let the sync counter, uh, slip :-)
+//                     if ((a[largestIdx] - a[i]) > 7.0)
+                       if ((a[largestIdx] - a[i]) > 9.0)
+                       {
+                               stepped = true;
+                               double ttn = (double)Global::wave[sNum[i]][sync[i]];
+                               a[i] += ttn;
+                               sync[i] += dir;
+#ifdef NOISY
+                               printf(" %4d ", (uint32_t)ttn);
+#endif
+                       }
+#ifdef NOISY
+                       else
+                               printf("      ");
+#endif
+               }
+
+               double sigma = StdDeviation(a, num);
+               double nextSigma = StdDeviationWave(sync, num);
+               uint32_t lookahead = LookaheadWave(sync, num, dir);
+#ifdef NOISY
+               printf("\n");
+
+               for(uint32_t i=0; i<num; i++)
+                       printf("<%4d>", (uint32_t)a[i]);
+
+               printf(" ==> %.2lf ", sigma);
+               printf("(next: %.2lf, la: %d)\n", nextSigma, lookahead);
+#endif
+               syncCount++;
+
+               // A handful of heuristics...  1st: If sigma is good, we're done
+               if (sigma < 2.50)
+                       keepGoing = false;
+
+               // Couldn't pull, so punt for now
+               if (!stepped)
+                       keepGoing = false;
+
+               // If the next sigma + current / 2 is OK, move on
+               if (((sigma + nextSigma) / 2.0) < 2.50)
+                       keepGoing = false;
+
+               // If the next sigma is good, and the lookahead is good, move on
+               // [Slight tweak: only do this if the current sigma isn't terrible]
+               if ((nextSigma < 2.50) && (lookahead > 10) && (sigma < 20.0))
+                       keepGoing = false;
+       }
+       while (keepGoing);
+
+       return true;
+}
+
+
+bool AttemptToFindStart(uint32_t * sync, uint32_t num)
+{
+       // Sanity check...
+       for(uint32_t i=0; i<num; i++)
+       {
+               if (sync[i] == 0)
+                       return true;
+       }
+
+       bool keepGoing = true;
+
+       do
+       {
+               double sigma = StdDeviationWave(sync, num);
+
+               if (sigma > 2.50)
+               {
+                       bool result = ResyncWave(sync, num, -1);
+
+                       if (result == false)
+                               return false;
+               }
+               else
+               {
+                       for(uint32_t i=0; i<num; i++)
+                               sync[i]--;
+               }
+
+               for(uint32_t i=0; i<num; i++)
+               {
+                       if (sync[i] == 0)
+                               keepGoing = false;
+               }
+       }
+       while (keepGoing);
+
+//#ifdef NOISY
+#if 1
+       for(uint32_t i=0; i<num; i++)
+               printf("Sync for stream %d: %d\n", i, sync[i]);
+       printf("Lookahead: %d\n", LookaheadWave(sync, num));
+#endif
+
+       return true;
+}
+
+
+bool InitialSync(uint32_t * sync, uint32_t num)
+{
+       // Let's try a different approach to this...
+       bool lookAt[6] = { true, true, false, false, false, false };
+
+//     while (FindSyncBetweenFirstTwo(sync) == false)
+       while (FindSyncBetweenFirstTwo(sync) < 1000)
+       {
+               for(uint32_t i=0; i<num; i++)
+               {
+                       sync[i] += 200;
+
+                       if (sync[i] >= Global::waveLen[sNum[i]])
+                       {
+                               printf("Could not find initial sync!!\n");
+                               return false;
+                       }
+               }
+       }
+
+       uint32_t lookahead = LookaheadWave(sync, 2);
+
+       if (lookAt[0])
+               printf("Found sync for streams 1 & 2 at %d and %d (la=%d)\n", sync[0], sync[1], lookahead);
+
+       // Add in the others, one at a time and try to synchronize them
+       uint32_t syncBest[6];
+
+       for(uint32_t i=2; i<num; i++)
+       {
+               lookAt[i] = true;
+               uint32_t bestLA = 0;
+
+               for(uint32_t j=0; j<200; j++)
+               {
+                       uint32_t syncSave = sync[i];
+
+                       for(uint32_t k=0; k<200; k++)
+                       {
+                               uint32_t la = LookaheadWave(sync, i + 1);
+
+                               if (la > bestLA)
+                               {
+                                       bestLA = la;
+                                       memcpy(syncBest, sync, sizeof(syncBest));
+                               }
+
+                               sync[i]++;
+                       }
+
+                       sync[i] = syncSave;
+
+                       // Kick all the other streams forward to check the rest...
+                       for(uint32_t k=0; k<i; k++)
+                               sync[k]++;
+               }
+
+               memcpy(sync, syncBest, sizeof(syncBest));
+       }
+
+       for(uint32_t i=0; i<num; i++)
+               printf("Sync for stream %d: %d (%s)\n", i, sync[i], (lookAt[i] ? "yes" : "no"));
+       printf("Lookahead: %d\n", LookaheadWave(sync, num));
+
+       return true;
+}
+
+
+uint32_t LoopLookahead(uint32_t trackNum, uint32_t start, uint32_t loopPoint, bool * test = NULL);
+uint32_t LoopLookahead(uint32_t trackNum, uint32_t start, uint32_t loopPoint, bool * test/*= NULL*/)
+{
+       uint32_t count = 0;
+       bool equal = true;
+       double a[2];
+
+       for(uint32_t i=loopPoint, pos=start; i<Global::synWaveLen[trackNum]; i++, pos++)
+       {
+               a[0] = Global::synWave[trackNum][pos];
+               a[1] = Global::synWave[trackNum][i];
+               double sigma = StdDeviation(a, 2);
+
+               if (sigma > 2.50)
+               {
+                       equal = false;
+                       break;
+               }
+
+               count++;
+       }
+
+       if (test)
+               *test = equal;
+
+       return count;
+}
+
+
+#define NOISYSYNTH
+//#define DEBUGSYNTH
+void SynthesizeTrack(uint32_t trackNum)
+{
+       uint32_t num = 0;
+       uint32_t sync[6] = { 0 };
+
+       for(uint32_t i=0; i<Global::numStreams; i++)
+       {
+               // Skip streams that aren't on the current track & BITS captures
+               if ((Global::stream[i]->location != trackNum)
+                       || (Global::stream[i]->captureType == 2))
+                       continue;
+
+#ifdef DEBUGSYNTH
+printf("sNum[%d] = %d\n", num, i);
+#endif
+               // Save the stream # so we can find it later
+               sNum[num++] = i;
+       }
+
+       // We should just bypass the synthesis part of this, not the loop point finding...  :-P  !!! FIX !!!
+       if (num == 1)
+       {
+               printf("%.2f: Single stream, length: %d\n", (float) trackNum / 4.0f, Uint32LE(Global::stream[sNum[0]]->dataLength));
+
+               memcpy(Global::synWave[trackNum], Global::wave[sNum[0]], Global::waveLen[sNum[0]] * 4);
+               Global::synWaveLen[trackNum] = Global::waveLen[sNum[0]];
+       }
+
+/*
+This is failing for track 9.00: it finds an initial sync @ 202, 200, la=1257 but real sync point is 0,2,2 (it says 5,0,0, which is wrong)
+*/
+       if (num > 1)
+       {
+               InitialSync(sync, num);
+               AttemptToFindStart(sync, num);
+
+               uint32_t count = 0, bloops = 0;
+               bool keepGoing = true;
+               Global::synWaveLen[trackNum] = 0;
+               double mean;
+
+               do
+               {
+                       double sigma = StdDeviationWave(sync, num, &mean);
+
+                       if (sigma <= 2.50)
+                       {
+                               count++;
+                               Global::synWave[trackNum][Global::synWaveLen[trackNum]] = (uint32_t)(mean + 0.5);
+                               Global::synWaveLen[trackNum]++;
+
+                               for(uint32_t i=0; i<num; i++)
+                                       sync[i]++;
+                       }
+                       else
+                       {
+#ifdef NOISYSYNTH
+                       uint32_t startOfSynth = Global::synWaveLen[trackNum];
+#endif
+#ifdef NOISYSYNTH
+                               if (bloops < 2)
+                               {
+                                       printf("Bloop seen at pos ");
+                                       for(uint32_t k=0; k<num; k++)
+                                               printf("%d%s", sync[k], (k == num - 1 ? "" : ", "));
+                                       printf("...\n");
+                               }
+#endif
+                               bloops++;       // Count the # of times we've had to punt
+                               uint32_t syncSave[6] = { 0 };
+                               memcpy(syncSave, sync, sizeof(syncSave));
+                               bool result = ResyncWave(sync, num);
+
+                               // Now go through the catty wampus crap and zero out the parts that aren't all ones across the board
+                               double timeToOnes = 0;
+                               double a[6], currentRow[6];
+
+                               // Collect the current row
+                               for(uint32_t i=0; i<num; i++)
+                               {
+                                       currentRow[i] = (double)Global::wave[sNum[i]][syncSave[i]];
+                                       syncSave[i]++;
+                               }
+#ifdef DEBUGSYNTH
+for(uint32_t i=0; i<num; i++)
+       printf("syncSave[%d]=%d (sync: %d)\n", i, syncSave[i], sync[i]);
+#endif
+
+                               while (true)
+                               {
+                                       if (Equal(syncSave, sync, num))
+                                               break;
+#ifdef DEBUGSYNTH
+printf("syncSave: ");
+for(uint32_t i=0; i<num; i++)
+       printf("%d%s", syncSave[i], (i == num - 1 ? "" : ", "));
+printf("\n    sync: ");
+for(uint32_t i=0; i<num; i++)
+       printf("%d%s", sync[i], (i == num - 1 ? "" : ", "));
+printf("\n");
+#endif
+
+                                       uint32_t amplitude = 1;
+                                       uint32_t smallestIdx = SmallestIndex(currentRow, num);
+                                       uint32_t cnt = 1;
+                                       a[0] = currentRow[smallestIdx];
+#ifdef DEBUGSYNTH
+printf("a[0]=%.2lf:\n", a[0]);
+#endif
+
+                                       for(uint32_t i=0; i<num; i++)
+                                       {
+                                               // Make sure we haven't gone beyond the end of any of the streams we're looking at
+                                               if (syncSave[i] >= Global::waveLen[sNum[i]])
+                                               {
+                                                       printf("Ran past end of stream %d (stream %d): syncSave=%d, waveLen=%d\n", i, sNum[i], syncSave[i], Global::waveLen[sNum[i]]);
+                                                       return;
+                                               }
+
+                                               if (i == smallestIdx)
+                                               {
+                                                       // Maybe we should chuck this above the if()?
+//                                                     if (syncSave[i] == sync[i])
+//                                                             continue;
+
+                                                       // We always pick up the smallest in the current set, since that's our basis
+//the reason this works is because this simulates the "add next and subtract smallest", since the subtraction of the smallest would always be zero.  :-P
+                                                       currentRow[i] = Global::wave[sNum[i]][syncSave[i]];
+//                                                     currentRow[i] += Global::wave[sNum[i]][syncSave[i]];
+                                                       syncSave[i]++;
+#ifdef DEBUGSYNTH
+printf("\t<%.2lf> (i=%d)\n", currentRow[i], i);
+#endif
+                                                       continue;
+                                               }
+
+                                               // Save the current row & subtract out the smallest as a basis
+                                               double crSave = currentRow[i];
+                                               currentRow[i] -= a[0];
+
+                                               // Don't bother with stuff that's out of range (@ current sync point!)  :-P
+                                               if (syncSave[i] == sync[i])
+                                                       continue;
+
+                                               // Try to find correlates
+                                               a[cnt] = crSave;
+                                               cnt++;
+                                               sigma = StdDeviation(a, cnt);
+#ifdef DEBUGSYNTH
+printf("\t");
+for(uint32_t j=1; j<cnt; j++)
+       printf("[%.2lf]", a[j]);
+#endif
+
+//relaxed sigma...
+                                               if (sigma <= 5.5)//SIGMA_THRESHOLD)
+                                               {
+                                                       // If the sigma is in range for this item, pick it up
+//                                                     currentRow[i] = (double)Global::wave[sNum[i]][syncSave[i]];
+                                                       currentRow[i] += (double)Global::wave[sNum[i]][syncSave[i]];
+                                                       syncSave[i]++;
+
+#ifdef DEBUGSYNTH
+printf("{%.2lf}", currentRow[i]);
+#endif
+                                                       amplitude++;
+                                               }
+                                               else
+                                               {
+                                                       // Otherwise reject the last item; it's too far out
+                                                       cnt--;
+                                               }
+#ifdef DEBUGSYNTH
+printf(" ==> %.2lf\n", sigma);
+#endif
+                                       }
+
+                                       // Get the average of the items picked up and add it to the wave
+                                       sigma = StdDeviation(a, cnt, &mean);
+                                       timeToOnes += mean;
+
+                                       // Did we find the line of ones yet?  If so, chuck it in the wave
+                                       if (amplitude == num)
+                                       {
+                                               Global::synWave[trackNum][Global::synWaveLen[trackNum]] = (uint32_t)(timeToOnes + 0.5);
+                                               Global::synWaveLen[trackNum]++;
+                                               timeToOnes = 0;
+                                       }
+#ifdef DEBUGSYNTH
+printf("\t");
+for(uint32_t j=0; j<num; j++)
+       printf("_%.2lf_", currentRow[j]);
+printf("\n\n");
+#endif
+                               }
+
+                               // Finally, chuck the final line of ones in
+                               sigma = StdDeviation(currentRow, num, &mean);
+                               timeToOnes += mean;
+                               Global::synWave[trackNum][Global::synWaveLen[trackNum]] = (uint32_t)(timeToOnes + 0.5);
+                               Global::synWaveLen[trackNum]++;
+#ifdef NOISYSYNTH
+printf("Blip @ %d: ", startOfSynth);
+for(uint32_t w=startOfSynth; w<Global::synWaveLen[trackNum]; w++)
+       printf("%d%s", Global::synWave[trackNum][w], (w == Global::synWaveLen[trackNum] - 1 ? "" : ", "));
+printf("\n");
+#endif
+                       }
+
+                       for(uint32_t i=0; i<num; i++)
+                       {
+                               if (sync[i] >= Global::waveLen[sNum[i]])
+                               {
+                                       keepGoing = false;
+                                       break;
+                               }
+                       }
+               }
+               while (keepGoing);
+
+               printf("\n%.2f: Synthesis done. Bit count: %d, bloop count: %d\n", (float)trackNum / 4.0f, count, bloops);
+       }
+
+       // Now, find the loop point and make BITS from it
+/*
+Now, we take the track and make an ouroborus out of it by finding the sync point.  We can also possibly use it to get rid of more false ones like we did above with the resynchronization code.  So how do we do this?
+
+We could use an approach similar to the original sync between 1 & 2, but there's no guarantee that the lookahead will be good right away.  So we need to do a combination where we count the places where it coincides well and plow through spots where it doesn't (and possibly mask any ones in those areas if it's a good match).
+
+We can start with the estimated loop point that the Applesauce hardware found, by walking it a bit before that point we can make sure we don't miss it.
+*/
+       // We use the loop point from stream #1 because we're lazy
+       uint32_t estLoopTime = Uint32LE(Global::stream[sNum[0]]->estLoopPoint);
+       uint32_t curTime = 0;
+       uint32_t pos = 0, startOfLoop = 0;
+       double a[2];
+       uint32_t maxLookahead = 0;
+       uint32_t maxPos = 0;
+       bool full, full2, full0, full1;
+       uint32_t blips, worstBlips, longestStretch, stretch, maxLongestStretch = 0, worstBlipsPos = 0, mlsPos = 0;
+       worstBlips = 1e9;
+
+       // Get the index to the correct time in "pos"
+       while (curTime < estLoopTime)
+               curTime += Global::synWave[trackNum][pos++];
+
+printf("%.2f: estLoopTime=%d, curTime=%d, pos=%d\n", (float)trackNum / 4.0f, estLoopTime, curTime, pos);
+       uint32_t posSave = pos;
+
+       // "pos" now holds the start of the search for our loop point.
+       for(uint32_t i=0; i<200; i++)
+       {
+               uint32_t lookahead = 0;
+               uint32_t j, pos0;
+               bool first = true;
+               blips = 0;
+               longestStretch = stretch = 0;
+               startOfLoop = 0;//shouldn't be necessary...
+
+               for(j=(pos+i-100), pos0=0; j<Global::synWaveLen[trackNum]; j++, pos0++)
+               {
+                       uint32_t lla0 = LoopLookahead(trackNum, pos0 + 0, j, &full0);
+                       uint32_t lla1 = LoopLookahead(trackNum, pos0 + 1, j, &full1);
+
+                       lookahead += lla0;
+                       stretch = lla0;
+
+                       if (stretch > longestStretch)
+                               longestStretch = stretch;
+
+                       if (full0)
+                       {
+                               break;
+                       }
+                       else if (full1 && first) // only check 1st time (for now)
+                       {
+                               startOfLoop = 1;
+                               lookahead = lla1;
+                               stretch = lla1;
+                               break;
+                       }
+
+                       if (first)
+                               first = false;
+
+                       pos0 += lla0;
+                       j += lla0;
+
+                       a[0] = Global::synWave[trackNum][pos0++];
+                       a[1] = Global::synWave[trackNum][j++];
+                       double sigma = StdDeviation(a, 2);
+
+#if 0
+if (first)
+{
+       first = false;
+//     printf("First blip: %.0lf, %.0lf (sigma=%.2lf) [pos=%d, la=%d]\n", a[0], a[1], sigma, i + pos - 100, pos0);
+
+       if (trackNum == 137)
+       {
+               uint32_t lla = LoopLookahead(trackNum, 0, j, &full);
+               uint32_t llap1 = LoopLookahead(trackNum, 1, j, &full2);
+               printf("%.2f: pos0=%d, j=%d, sigma=%lf, la=%d%s, la+1=%d%s", (float)trackNum / 4.0f, pos0, j, sigma, lla, (full ? " *equal" : ""), llap1, (full2 ? " *equal" : ""));
+       }
+}
+#endif
+
+/*                     if (sigma <= 2.50)
+                       {
+                               lookahead++;
+                               stretch++;
+
+                               if (stretch > longestStretch)
+                                       longestStretch = stretch;
+                       }
+                       else//*/
+//                     {
+                               // Hmm, not in sync.  See if we can re-sync
+                               stretch = 0;
+                               blips++;
+
+                               do
+                               {
+                                       if (a[0] < a[1])
+                                               a[0] += Global::synWave[trackNum][pos0++];
+                                       else
+                                               a[1] += Global::synWave[trackNum][j++];
+
+                                       // Maybe put all the other heuristics in too?
+                                       if (StdDeviation(a, 2) <= 2.50)
+                                               break;
+
+                                       // Now you've gone *too* far...
+                                       if (j >= Global::synWaveLen[trackNum])
+                                               break;
+                               }
+                               while (true);
+//                     }
+               }
+
+#if 0
+if (trackNum == 137)
+       printf(" blips=%d, la=%d\n", blips, lookahead);
+#endif
+
+//maybe we should keep an array of the analyses so we can decide afterward which one is best...
+               if (blips < worstBlips)
+               {
+                       worstBlips = blips;
+                       worstBlipsPos = pos + i - 100;
+               }
+
+               if (lookahead > maxLookahead)
+               {
+                       maxLookahead = lookahead;
+                       maxPos = pos + i - 100;
+               }
+
+               if (longestStretch > maxLongestStretch)
+               {
+                       maxLongestStretch = longestStretch;
+                       mlsPos = pos + i - 100;
+               }
+
+               if (blips == 0)
+                       break;
+       }
+
+#if 0
+       bitLen[trackNum] = RenderBitstream(bits[trackNum], &byteLen[trackNum], Global::synWave[trackNum], startOfLoop, maxPos);
+#endif
+
+       printf("%.2f: Synthesized wave length: %d\n", (float)trackNum / 4.0f    , Global::synWaveLen[trackNum]);
+       printf("%s loop point found at position %d (elp%+d, la=%d, startPos=%d, blips=%d, blipsPos=%d, longest stretch=%d, mlsPos=%d, sol=%d)\n----------------------------------------------------------------------\n", (blips == 0 ? "Perfect" : "Possible"), maxPos, maxPos - posSave, maxLookahead, pos, worstBlips, worstBlipsPos, maxLongestStretch, mlsPos, startOfLoop);
+/*
+Track 1.00:
+36110 is the loop point.  But it fails to find it for some reason. [Because it jumped on the first one it found instead of the longest...]
+*/
+
+/*     for(uint32_t i=0; i<maxLookahead+5; i++)
+       {
+               a[0] = Global::synWave[trackNum][i];
+               a[1] = Global::synWave[trackNum][i + maxPos];
+               double sigma = StdDeviation(a, 2);
+               printf("[%.2lf]", sigma);
+       }
+
+       printf("\n");//*/
+}
+
+
+/*
+Using a histogram, we can get an idea of the drift from the ones:
+
+                @@
+                @@
+                @@
+                @@
+                @@
+                @@
+                @@
+                @@        @@
+                @@        @@
+                @@        @@
+                @@        @@
+                @@        @@
+                @@   @@   @@
+           @@   @@   @@   @@
+           @@   @@   @@   @@
+      @@   @@   @@   @@   @@
+-------------------------------------------------
+0000|0584|1792|9611|2627|5382|0482|0058|0013|0000
+ 28   29   30   31   32   33   34   35   36   37
+
+Peak of the ones occurs at 31, with a secondary at 33. Twos drift:
+
+                @@
+                @@        @@
+                @@        @@
+                @@        @@
+                @@        @@
+                @@        @@
+                @@        @@
+                @@   @@   @@
+      @@        @@   @@   @@
+-------------------------------------------------
+0000|0545|0277|5482|1223|5168|0252|0082|0102|0000
+ 57   58   59   60   61   62   63   64   65   66
+
+This looks like stretched out ones (they might all be spurious...):
+
+      @@
+      @@
+      @@             @@
+      @@             @@
+      @@   @@        @@
+      @@   @@        @@
+      @@   @@        @@
+      @@   @@   @@   @@        @@
+---------------------------------------
+0000|0015|0007|0002|0011|0001|0002|0000
+ 43   44   45   46   47   48   49   50
+
+
+*/
+
+
diff --git a/src/dsp.h b/src/dsp.h
new file mode 100644 (file)
index 0000000..030446f
--- /dev/null
+++ b/src/dsp.h
@@ -0,0 +1,50 @@
+#ifndef __DSP_H__
+#define __DSP_H__
+
+#include <stdint.h>
+#include <stdlib.h>
+
+double StdDeviation(double *, uint32_t, double * mean = NULL);
+double Largest(double *, uint32_t);
+uint32_t Largest(uint32_t *, uint32_t);
+uint32_t LargestIndex(double *, uint32_t);
+uint32_t LargestIndex(uint32_t *, uint32_t);
+double Smallest(double *, uint32_t);
+uint32_t Smallest(uint32_t *, uint32_t);
+uint32_t SmallestIndex(double *, uint32_t);
+uint32_t SmallestIndex(uint32_t *, uint32_t);
+
+#if 0
+uint32_t Synthesize(uint32_t * sync, uint32_t num, uint32_t * wave, float * amp);
+bool FindSync(uint32_t, uint32_t, uint32_t &, uint32_t &);
+void FindSyncForStreams(uint32_t * sync, uint32_t num);
+void FindInitialSyncForStreams(uint32_t * sync, uint32_t num);
+void BacktrackInitialSync(uint32_t * sync, uint32_t num);
+void BacktrackInitialSync2(uint32_t * sync, uint32_t num);
+void BacktrackInitialSync3(uint32_t * sync, uint32_t num);
+void BacktrackInitialSync4(uint32_t * sync, uint32_t num);
+void StepBackUntilBad(uint32_t * sync, double * a, uint32_t num);
+bool StepBackThruBad(uint32_t * sync, double * a, uint32_t num);
+void StepBack(uint32_t * sync, double * a, uint32_t num);
+void StepAndAddBack(uint32_t * sync, double * a, uint32_t num);
+void StepAndAddBack(uint32_t & sync, double & a, uint32_t i);
+void StepForward(uint32_t * sync, double * a, uint32_t num);
+void StepAndAddForward(uint32_t * sync, double * a, uint32_t num);
+void StepAndAddForward(uint32_t & sync, double & a, uint32_t i);
+uint32_t Lookahead(uint32_t * sync, uint32_t num, int32_t dir = 1);
+int Resync(uint32_t * sync, double * a, uint32_t num, int32_t dir = 1);
+#endif
+void FindInitialSyncForStreams2(uint32_t * sync, uint32_t num);
+uint32_t Synthesize2(uint32_t * sync, uint32_t num, uint32_t * wave, float * amp);
+
+bool AttemptToFindStart(uint32_t * sync, uint32_t num);
+bool InitialSync(uint32_t * sync, uint32_t num);
+void SynthesizeTrack(uint32_t trackNum);
+
+// Exported variables
+extern uint32_t sNum[];
+//extern double ratio[];
+extern double initSyncTime[];
+
+#endif // __DSP_H__
+
diff --git a/src/fileio.cpp b/src/fileio.cpp
new file mode 100644 (file)
index 0000000..a70b4ca
--- /dev/null
@@ -0,0 +1,80 @@
+//
+// fileio.cpp: File I/O
+//
+// Part of the WOZ Maker project
+// by James Hammons
+// (C) 2018 Underground Software
+// See the README and GPLv3 files for licensing and warranty information
+//
+
+#include "fileio.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+
+static uint32_t crcTable[256] =
+{
+       0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
+       0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
+       0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
+       0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
+       0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
+       0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
+       0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
+       0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
+       0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
+       0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
+       0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
+       0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
+       0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
+       0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
+       0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
+       0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
+       0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
+       0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
+       0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
+       0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
+       0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
+       0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
+       0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
+       0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
+       0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
+       0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
+       0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
+       0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
+       0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
+       0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
+       0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
+       0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
+};
+
+
+uint32_t CRC32(const uint8_t * data, uint32_t length)
+{
+       uint32_t crc = 0xFFFFFFFF;
+
+       for(uint32_t i=0; i<length; i++)
+               crc = crcTable[(crc ^ *data++) & 0xFF] ^ (crc >> 8);
+
+       return ~crc;
+}
+
+
+uint8_t * ReadFile(const char * filename, uint32_t * size)
+{
+       FILE * fp = fopen(filename, "r");
+
+       if (!fp)
+               return NULL;
+
+       fseek(fp, 0, SEEK_END);
+       *size = ftell(fp);
+       fseek(fp, 0, SEEK_SET);
+
+       uint8_t * buffer = (uint8_t *)malloc(*size);
+       fread(buffer, 1, *size, fp);
+       fclose(fp);
+
+       return buffer;
+}
+
diff --git a/src/fileio.h b/src/fileio.h
new file mode 100644 (file)
index 0000000..0ee24d2
--- /dev/null
@@ -0,0 +1,135 @@
+#ifndef __FILEIO_H__
+#define __FILEIO_H__
+
+#include <stdint.h>
+
+// N.B.: All 32/16-bit values are stored in little endian.  Which means, to
+//       read/write them safely, we need to use translators as this code may or
+//       may not be compiled on an architecture that supports little endian
+//       natively.
+
+struct A2RStream
+{
+       uint8_t location;               // Quarter track for this stream
+       uint8_t captureType;    // 1 = timing, 2 = bits, 3 = ext. timing
+       uint8_t dataLength[4];  // Length of the stream
+       uint8_t estLoopPoint[4];// Estimated loop point in ticks (125 ns/tick)
+       uint8_t data[];                 // Variable length array for stream data
+};
+
+struct A2RMetadata
+{
+       uint8_t metaTag[4];             // "META"
+       uint32_t metaSize;              // Size of the META chunk
+       uint8_t data[];                 // Variable length array of metadata
+};
+
+struct A2R
+{
+       // Header
+       uint8_t magic1[4];              // "A2R2"
+       uint8_t magic2[4];              // $FF $0A $0D $0A
+
+       // INFO chunk
+       uint8_t infoTag[4];             // "INFO"
+       uint32_t infoSize;              // Always 36 bytes long
+       uint8_t infoVersion;    // Currently 1
+       uint8_t creator[32];    // Software that made this image, padded with 0x20
+       uint8_t diskType;               // 1 = 5 1/4", 2 = 3 1/2"
+       uint8_t writeProtected; // 1 = write protected disk
+       uint8_t synchronized;   // 1 = cross-track sync was used during imaging
+
+       // STRM chunk
+       uint8_t strmTag[4];             // "STRM"
+       uint32_t strmSize;              // Varies, depending on # of tracks imaged
+       uint8_t data[];                 // Variable length array for stream data proper
+};
+
+struct WOZTrack
+{
+       uint8_t bits[6646];
+       uint16_t byteCount;
+       uint16_t bitCount;
+       uint16_t splicePoint;
+       uint8_t spliceNibble;
+       uint8_t spliceBitCount;
+       uint16_t reserved;
+};
+
+struct WOZMetadata
+{
+       uint8_t metaTag[4];             // "META"
+       uint32_t metaSize;              // Size of the META chunk
+       uint8_t data[];                 // Variable length array of metadata
+};
+
+struct WOZ
+{
+       // Header
+       uint8_t magic1[4];              // "WOZ1"
+       uint8_t magic2[4];              // $FF $0A $0D $0A
+       uint32_t crc32;                 // CRC32 of the remaining data in the file
+
+       // INFO chunk
+       uint8_t infoTag[4];             // "INFO"
+       uint32_t infoSize;              // Always 60 bytes long
+       uint8_t infoVersion;    // Currently 1
+       uint8_t diskType;               // 1 = 5 1/4", 2 = 3 1/2"
+       uint8_t writeProtected; // 1 = write protected disk
+       uint8_t synchronized;   // 1 = cross-track sync was used during imaging
+       uint8_t cleaned;                // 1 = fake bits removed from image
+       uint8_t creator[32];    // Software that made this image, padded with 0x20
+       uint8_t pad1[23];               // Padding to 60 bytes
+
+       // TMAP chunk
+       uint8_t tmapTag[4];             // "TMAP"
+       uint32_t tmapSize;              // Always 160 bytes long
+       uint8_t tmap[160];              // Track map, with empty tracks set to $FF
+
+       // TRKS chunk
+       uint8_t trksTag[4];             // "TRKS"
+       uint32_t trksSize;              // Varies, depending on # of tracks imaged
+       WOZTrack track[];               // Variable length array for the track data proper
+};
+
+
+// Exported functions
+uint32_t CRC32(const uint8_t * data, uint32_t length);
+uint8_t * ReadFile(const char * filename, uint32_t * size);
+
+
+// Inline functions ("get" functions--need to write "set" functions)
+static inline uint16_t Uint16LE(uint16_t v)
+{
+       uint8_t * w = (uint8_t *)&v;
+       return (w[1] << 8) | (w[0] << 0);
+}
+
+static inline uint32_t Uint32LE(uint32_t v)
+{
+       uint8_t * w = (uint8_t *)&v;
+       return (w[3] << 24) | (w[2] << 16) | (w[1] << 8) | (w[0] << 0);
+}
+
+static inline uint32_t Uint32LE(uint8_t * v)
+{
+       return (v[3] << 24) | (v[2] << 16) | (v[1] << 8) | (v[0] << 0);
+}
+
+static inline uint32_t Uint32BE(uint8_t * v)
+{
+       return (v[0] << 24) | (v[1] << 16) | (v[2] << 8) | (v[3] << 0);
+}
+
+static inline void SwapBytes32(uint8_t * b)
+{
+       uint8_t temp = b[0];
+       b[0] = b[3];
+       b[3] = temp;
+       temp = b[1];
+       b[1] = b[2];
+       b[2] = temp;
+}
+
+#endif // __FILEIO_H__
+
diff --git a/src/global.cpp b/src/global.cpp
new file mode 100644 (file)
index 0000000..52b9fb9
--- /dev/null
@@ -0,0 +1,45 @@
+//
+// global.cpp: Global variables
+//
+// Those who think that global variables are evil have obviously not done any
+// amount of serious software development.  If you think that doing away with
+// this class will make it better, don't.  You don't know what you're doing.
+//
+// Part of the WOZ Maker project
+// by James Hammons
+// (C) 2018 Underground Software
+//
+
+#include "global.h"
+#include <stdio.h>
+#include "fileio.h"
+
+
+A2R * Global::a2r = NULL;
+uint32_t Global::a2rSize = 0;
+A2RMetadata * Global::metadata;
+A2RStream * Global::stream[800];
+uint32_t Global::numStreams = 0;
+uint8_t Global::bitStream[80000];
+uint32_t Global::bitStreamLength = 0;
+uint32_t Global::nibbleCount = 0;
+uint32_t Global::streamNum = 0;
+uint8_t Global::trackNum = 0;
+const uint8_t Global::bit[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
+uint8_t * Global::streamData[9] = { 0 };
+uint32_t Global::streamLen[9] = { 0 };
+uint8_t Global::streamCount = 0;
+uint32_t Global::synthWave[80000];
+float Global::swAmplitude[80000];
+uint32_t Global::swLen = 0;
+uint8_t Global::trackStatus[141] = { 0 };
+// N.B.: This takes 256MB (1/4 of a GB!) to hold the unpacked data. Seems excessive to me... (could probably determine at runtime how much mem is needed, and just allocate that on the heap...)
+uint32_t Global::wave[800][80000] = { 0 };
+uint32_t Global::waveLen[800] = { 0 };
+
+uint32_t Global::bloops = 0;
+uint32_t Global::waveSync = 0;
+
+uint32_t Global::synWave[141][80000] = { 0 };
+uint32_t Global::synWaveLen[141] = { 0 };
+
diff --git a/src/global.h b/src/global.h
new file mode 100644 (file)
index 0000000..1db173d
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef __GLOBAL_H__
+#define __GLOBAL_H__
+
+#include <stdint.h>
+
+class A2R;
+class A2RMetadata;
+class A2RStream;
+
+class Global
+{
+       // Static public variables accessible to all
+       public:
+               static A2R * a2r;
+               static uint32_t a2rSize;
+               static A2RMetadata * metadata;
+               static A2RStream * stream[800];
+               static uint32_t numStreams;
+               static uint8_t bitStream[80000];
+               static uint32_t bitStreamLength;
+               static uint32_t nibbleCount;
+               static uint32_t streamNum;
+               static uint8_t trackNum;
+               static const uint8_t bit[8];
+               static uint8_t * streamData[9]; // N.B.: Should never have more than 5
+               static uint32_t streamLen[9];
+               static uint8_t streamCount;
+               static uint32_t synthWave[80000];
+               static float swAmplitude[80000];
+               static uint32_t swLen;
+               static uint8_t trackStatus[141];
+               static uint32_t wave[800][80000];       // Unpacked raw timing wave
+               static uint32_t waveLen[800];           // Unpacked raw timing wave length
+               static uint32_t bloops;
+               static uint32_t waveSync;
+               static uint32_t synWave[141][80000];    // Synthesized wave
+               static uint32_t synWaveLen[141];                // Synthesized wave length
+};
+
+#endif // __GLOBAL_H__
+
diff --git a/src/infowidget.cpp b/src/infowidget.cpp
new file mode 100644 (file)
index 0000000..90cca3e
--- /dev/null
@@ -0,0 +1,131 @@
+//
+// infowidget.cpp: A2R disk image info widget
+//
+// Part of the WOZ Maker Project
+// by James Hammons
+// (C) 2018 Underground Software
+// See the README and GPLv3 files for licensing and warranty information
+//
+
+#include "infowidget.h"
+#include "fileio.h"
+#include "global.h"
+
+
+InfoWidget::InfoWidget(void): QWidget()
+{
+       label = new QLabel;
+
+       QVBoxLayout * mainLayout = new QVBoxLayout;
+       mainLayout->addWidget(label);
+       mainLayout->addStretch();
+
+       setLayout(mainLayout);
+}
+
+
+InfoWidget::~InfoWidget()
+{
+}
+
+
+void InfoWidget::ShowInfo(void)
+{
+#if 0
+       const char objName[OTCount][16] = {
+               "None", "Line", "Circle", "Ellipse", "Arc", "Polygon", "Dimension", "Spline", "Text", "Container"
+       };
+       const char dimName[DTCount][32] = {
+               "Linear", "Vertical", "Horizontal", "Radial", "Diametric",
+               "Circumferential", "Angular", "Leader"
+       };
+
+       // Sanity check
+       if (obj == NULL)
+               return;
+
+       QString s = QString("<b>%1</b><br><br>").arg(QString(objName[obj->type]));
+
+       switch (obj->type)
+       {
+       case OTLine:
+       {
+               Vector line(obj->p[0], obj->p[1]);
+               s += QString("&lt;%1, %2&gt; to &lt;%3, %4&gt;<br>Length: %5<br>Angle: %6&#x00B0;<br>").arg(obj->p[0].x).arg(obj->p[0].y).arg(obj->p[1].x).arg(obj->p[1].y).arg(line.Magnitude()).arg(line.Angle() * RADIANS_TO_DEGREES);
+               break;
+       }
+
+       case OTCircle:
+               s += QString("Center: &lt;%1, %2&gt;<br>Radius: %3<br>").arg(obj->p[0].x).arg(obj->p[0].y).arg(obj->radius[0]);
+               break;
+
+       case OTEllipse:
+               break;
+
+       case OTArc:
+               s += QString("Center: &lt;%1, %2&gt;<br>Radius: %3<br>Start: %4&#x00B0;<br>Span: %5&#x00B0;<br>").arg(obj->p[0].x).arg(obj->p[0].y).arg(obj->radius[0]).arg(obj->angle[0] * RADIANS_TO_DEGREES).arg(obj->angle[1] * RADIANS_TO_DEGREES);
+               break;
+
+       case OTPolygon:
+               break;
+
+       case OTDimension:
+       {
+               Dimension * d = (Dimension *)obj;
+               s += QString("Type: %1<br>").arg(dimName[d->subtype]);
+               break;
+       }
+
+       case OTSpline:
+               break;
+
+       case OTText:
+       {
+               Text * t = (Text *)obj;
+               s += QString("&lt;%1, %2&gt;<br>Width/Height: %3/%4<br>Angle: %5&#x00B0;<br>").arg(t->p[0].x).arg(t->p[0].y).arg(t->extents.Width()).arg(t->extents.Height()).arg(obj->angle[0] * RADIANS_TO_DEGREES);
+               break;
+       }
+
+       case OTContainer:
+               break;
+
+       default:
+               break;
+       }
+#endif
+       uint8_t buf[33];
+       memcpy(buf, Global::a2r->creator, 32);
+       buf[32] = 0;
+
+       QString s;
+       s += QString("No. Streams: %1<br>").arg(Global::numStreams);
+       s += QString("Creator: %1<br>").arg((char *)buf);
+       s += QString("Disk Type: %1<br>").arg(Global::a2r->diskType == 1 ? "5 1/4\"" : (Global::a2r->diskType == 2 ? "3 1/2\"" : "Unknown"));
+       s += QString("Write Protected: %1<br>").arg(Global::a2r->writeProtected == 1 ? "Yes" : "No");
+       s += QString("Synchronized: %1<br>").arg(Global::a2r->writeProtected == 1 ? "Yes" : "No");
+
+       if (Global::metadata != NULL)
+       {
+               uint32_t size = Uint32LE(Global::metadata->metaSize);
+               uint8_t * data = Global::metadata->data;
+               uint32_t pos = 0;
+
+               while (pos < size)
+               {
+                       if (data[pos] == 0x09)
+                               s += ": ";
+                       else if (data[pos] == 0x0A)
+                               s += "<br>";
+                       else
+                               s += data[pos];
+
+                       pos++;
+               }
+       }
+
+//     s += QString("Stream No.: %1<br>").arg(Global::streamNum);
+//     s += QString("Nibbles: %1<br>").arg(Global::nibbleCount);
+
+       label->setText(s);
+}
+
diff --git a/src/infowidget.h b/src/infowidget.h
new file mode 100644 (file)
index 0000000..4c9a97b
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef __INFOWIDGET_H__
+#define __INFOWIDGET_H__
+
+#include <QtWidgets>
+
+class InfoWidget: public QWidget
+{
+       Q_OBJECT
+
+       public:
+               InfoWidget(void);
+               ~InfoWidget();
+
+       public slots:
+               void ShowInfo(void);
+
+       private:
+               QLabel * label;
+};
+
+#endif // __INFOWIDGET_H__
+
diff --git a/src/mainwidget.cpp b/src/mainwidget.cpp
new file mode 100644 (file)
index 0000000..e6d2e1c
--- /dev/null
@@ -0,0 +1,130 @@
+//
+// mainwidget.cpp: Main window display widget
+//
+// Part of the WOZ Maker project
+// by James Hammons
+// (C) 2018 Underground Software
+//
+
+#include "mainwidget.h"
+#include "diskwidget.h"
+#include "nibblewidget.h"
+#include "waveformwidget.h"
+
+
+MainWidget::MainWidget(QWidget * parent/*= 0*/): QWidget(parent)
+{
+       QVBoxLayout * layout = new QVBoxLayout;
+
+       wfWidget = new WaveformWidget(this);
+//     wfWidget->setGeometry(QRect(0, 0, 20, 300));
+
+       QScrollArea * scroll1 = new QScrollArea;
+
+       // set black background
+       QPalette pal = palette();
+       pal.setColor(QPalette::Window, QColor(0x3B, 0x36, 0x32));
+       scroll1->setAutoFillBackground(true);
+       scroll1->setPalette(pal);
+       scroll1->setWidget(wfWidget);
+
+//     wfWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+
+       nibbleWidget = new NibbleWidget(this);
+//     nibbleWidget->setGeometry(QRect(0, 0, 20, 20));
+//     nibbleWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+
+       QScrollArea * scroll2 = new QScrollArea;
+       pal.setColor(QPalette::Window, QColor(0xFF, 0xFF, 0xFF));
+       scroll2->setAutoFillBackground(true);
+       scroll2->setPalette(pal);
+       scroll2->setWidget(nibbleWidget);
+
+       diskWidget = new DiskWidget(this);
+       diskWidget->setAutoFillBackground(true);
+       diskWidget->setPalette(pal);
+
+       layout->addWidget(scroll1);
+//     layout->addWidget(scroll2);
+       layout->addWidget(diskWidget);
+
+       setLayout(layout);
+
+       wfWidget->setFocusPolicy(Qt::StrongFocus);      // Without this, it gets no keys
+}
+
+
+MainWidget::~MainWidget(void)
+{
+}
+
+
+void MainWidget::mousePressEvent(QMouseEvent * event)
+{
+       if (event->button() == Qt::LeftButton)
+       {
+               event->accept();
+       }
+}
+
+
+void MainWidget::mouseMoveEvent(QMouseEvent * event)
+{
+       if (event->buttons() & Qt::LeftButton)
+       {
+               event->accept();
+       }
+}
+
+
+void MainWidget::mouseReleaseEvent(QMouseEvent * event)
+{
+       if (event->button() == Qt::LeftButton)
+       {
+               event->accept();
+       }
+}
+
+
+void MainWidget::mouseDoubleClickEvent(QMouseEvent * event)
+{
+       if (event->button() == Qt::LeftButton)
+       {
+               event->accept();
+       }
+}
+
+
+void MainWidget::keyPressEvent(QKeyEvent * event)
+{
+       int key = event->key();
+
+       if (key == Qt::Key_Up)
+       {
+       }
+       else if (key == Qt::Key_Down)
+       {
+       }
+       else if (key == Qt::Key_Left)
+       {
+       }
+       else if (key == Qt::Key_Right)
+       {
+       }
+       else
+               return;
+
+       // Only update if a key we recognize has been pressed!
+       update();
+}
+
+
+void MainWidget::keyReleaseEvent(QKeyEvent * /*event*/)
+{
+}
+
+
+void MainWidget::resizeEvent(QResizeEvent * /*event*/)
+{
+}
+
diff --git a/src/mainwidget.h b/src/mainwidget.h
new file mode 100644 (file)
index 0000000..249ede6
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef __MAINWIDGET_H__
+#define __MAINWIDGET_H__
+
+#include <QtWidgets>
+#include <stdint.h>
+
+class WaveformWidget;
+class NibbleWidget;
+class DiskWidget;
+
+class MainWidget: public QWidget
+{
+       Q_OBJECT
+
+       public:
+               MainWidget(QWidget * parent = 0);
+               ~MainWidget();
+
+       protected:
+               void mousePressEvent(QMouseEvent * event);
+               void mouseMoveEvent(QMouseEvent * event);
+               void mouseReleaseEvent(QMouseEvent * event);
+               void mouseDoubleClickEvent(QMouseEvent * event);
+               void keyPressEvent(QKeyEvent * event);
+               void keyReleaseEvent(QKeyEvent * event);
+               void resizeEvent(QResizeEvent * event);
+
+       public:
+               WaveformWidget * wfWidget;
+               NibbleWidget * nibbleWidget;
+               DiskWidget * diskWidget;
+};
+
+#endif // __MAINWIDGET_H__
+
diff --git a/src/mainwin.cpp b/src/mainwin.cpp
new file mode 100644 (file)
index 0000000..528924d
--- /dev/null
@@ -0,0 +1,336 @@
+//
+// mainwin.cpp: Implementation of the MainWin class
+//
+// Part of the WOZ Maker project
+// by James Hammons
+// (C) 2018 Underground Software
+//
+
+#include "mainwin.h"
+
+#include <stdlib.h>                    // For rand()
+#include <time.h>                      // For time()
+#include "diskwidget.h"
+#include "fileio.h"
+#include "global.h"
+#include "infowidget.h"
+#include "mainwidget.h"
+#include "navwidget.h"
+#include "nibblewidget.h"
+#include "waveformwidget.h"
+
+
+MainWin::MainWin()
+{
+       mainWidget = new MainWidget(this);
+       setCentralWidget(mainWidget);
+
+       setWindowTitle("WOZ Maker");
+       setWindowIcon(QIcon(":/woz-icon.png"));
+
+       loadFile = CreateAction(tr("&Open"), tr("Open A2R"), tr("Open an A2R file"), QIcon(), QKeySequence(tr("ctrl+o")));
+       connect(loadFile, SIGNAL(triggered()), this, SLOT(HandleLoadFile()));
+
+       newGame = CreateAction(tr("&New"), tr("New Game"), tr("Start a new game of Warehouse Man Deluxe"), QIcon(), QKeySequence(tr("ctrl+n")));
+//     connect(newGame, SIGNAL(triggered()), this, SLOT(HandleNewGame()));
+
+       undoAction = CreateAction(tr("&Undo"), tr(""), tr(""), QIcon(), QKeySequence(tr("ctrl+z")));
+//     connect(undoAction, SIGNAL(triggered()), this, SLOT(HandleUndo()));
+
+       resetLevel = CreateAction(tr("&Reset Level"), tr("Reset Level"), tr("Start the current level over"), QIcon(), QKeySequence(tr("ctrl+r")));
+//     connect(resetLevel, SIGNAL(triggered()), this, SLOT(HandleReset()));
+
+       skipLevel = CreateAction(tr("&Skip Level"), tr("Skip Level"), tr("Skip the current level"), QIcon(), QKeySequence(tr("ctrl+k")));
+//     connect(skipLevel, SIGNAL(triggered()), this, SLOT(HandleSkipLevel()));
+
+       gameOptions = CreateAction(tr("&Options..."), tr("Options"), tr("Configure Warehouse Man Deluxe's options"), QIcon(), QKeySequence(tr("ctrl+o")));
+//     connect(gameOptions, SIGNAL(triggered()), this, SLOT(OnGameOptions()));
+
+       gameStats = CreateAction(tr("&Stats..."), tr("Game Stats"), tr("Show game stats"), QIcon(), QKeySequence(tr("ctrl+s")));
+//     connect(gameStats, SIGNAL(triggered()), this, SLOT(OnGameStats()));
+
+       appExit = CreateAction(tr("E&xit"), tr("Exit"), tr("Quit playing Warehouse Man Deluxe..."), QIcon(), QKeySequence(tr("ctrl+q")));
+       connect(appExit, SIGNAL(triggered()), this, SLOT(close()));
+
+       appAbout = CreateAction(tr("&About"), tr("About"), tr("Display program information..."), QIcon(), QKeySequence(tr("")));
+       connect(appAbout, SIGNAL(triggered()), this, SLOT(AboutWozMaker()));
+
+       // Get signals from the gameboard to update scores...
+//     connect(gameBoard, SIGNAL(UpdateScore(int)), this, SLOT(OnUpdateScore(int)));
+//     connect(gameWidget, SIGNAL(GameWasWon()), this, SLOT(WeHaveAWinner()));
+
+       // Connect editor to game widget...
+//     connect(editorWindow, SIGNAL(SetupLevel(Level *)), gameWidget,
+//             SLOT(HandlePlayGameFromEditor(Level *)));
+
+
+       QMenu * menu = menuBar()->addMenu(tr("&File"));
+       menu->addAction(loadFile);
+       menu->addSeparator();
+//     menu->addAction(undoAction);
+//     menu->addAction(resetLevel);
+//     menu->addAction(skipLevel);
+//     menu->addSeparator();
+//     menu->addAction(gameOptions);
+//     menu->addAction(gameStats);
+//     menu->addSeparator();
+       menu->addAction(appExit);
+
+       menu = menuBar()->addMenu(tr("&Help"));
+       menu->addAction(appAbout);
+
+//     statusBar()->addPermanentWidget(gameBoard->score);
+       statusBar()->showMessage(tr("Ready"));
+
+       // Create dock widgets
+       QDockWidget * dw1 = new QDockWidget("A2R Info", this);
+       infoWidget = new InfoWidget;
+       dw1->setWidget(infoWidget);
+       addDockWidget(Qt::RightDockWidgetArea, dw1);
+
+       QDockWidget * dw2 = new QDockWidget("Disk Nav", this);
+       navWidget = new NavWidget;
+       dw2->setWidget(navWidget);
+       addDockWidget(Qt::RightDockWidgetArea, dw2);
+
+       connect(navWidget, SIGNAL(UpdateWaveform()), mainWidget->wfWidget, SLOT(HandleUpdate()));
+       connect(navWidget, SIGNAL(InitSync()), mainWidget->wfWidget, SLOT(HandleInitSync()));
+       connect(navWidget, SIGNAL(StepBack()), mainWidget->wfWidget, SLOT(HandleStepBack()));
+       connect(navWidget, SIGNAL(ManualSync()), mainWidget->wfWidget, SLOT(HandleManualSync()));
+       connect(navWidget, SIGNAL(ZeroAll()), mainWidget->wfWidget, SLOT(HandleZeroAll()));
+       connect(navWidget, SIGNAL(Synthesize()), mainWidget->wfWidget, SLOT(HandleSynthesize()));
+       connect(navWidget, SIGNAL(Sync(int, int)), mainWidget->wfWidget, SLOT(HandleSync(int, int)));
+       connect(navWidget, SIGNAL(WaveSync(int)), mainWidget->wfWidget, SLOT(HandleWaveSync(int)));
+       connect(navWidget, SIGNAL(Ratio(int, int)), mainWidget->wfWidget, SLOT(HandleRatio(int, int)));
+       connect(navWidget, SIGNAL(Synthesize2()), mainWidget->wfWidget, SLOT(HandleSynthesize2()));
+
+       connect(mainWidget->diskWidget, SIGNAL(UpdateWaveform()), mainWidget->wfWidget, SLOT(HandleUpdate()));
+       connect(mainWidget->diskWidget, SIGNAL(UpdateInfo()), navWidget, SLOT(ShowInfo()));
+
+       connect(mainWidget->wfWidget, SIGNAL(UpdateInfo()), navWidget, SLOT(ShowInfo()));
+
+       QSettings settings("Underground Software", "WOZ Maker");
+       QPoint mainWinPosition = settings.value("pos", QPoint(200, 100)).toPoint();
+       move(mainWinPosition);
+       QSize mainWinSize = settings.value("size", QSize(500, 500)).toSize();
+       resize(mainWinSize);
+       lastDir = settings.value("lastDir", "").toString();
+}
+
+
+MainWin::~MainWin()
+{
+       if (Global::a2r)
+               free(Global::a2r);
+}
+
+
+//
+// Consolidates action creation from a multi-step process to a single-step one.
+//
+QAction * MainWin::CreateAction(QString name, QString tooltip, QString statustip,
+       QIcon icon, QKeySequence key, bool checkable/*= false*/)
+{
+       QAction * action = new QAction(icon, name, this);
+       action->setToolTip(tooltip);
+       action->setStatusTip(statustip);
+       action->setShortcut(key);
+       action->setCheckable(checkable);
+
+       return action;
+}
+
+
+//
+// This is essentially the same as the previous function, but this allows more
+// than one key sequence to be added as key shortcuts.
+//
+QAction * MainWin::CreateAction(QString name, QString tooltip, QString statustip,
+       QIcon icon, QKeySequence key1, QKeySequence key2, bool checkable/*= false*/)
+{
+       QAction * action = new QAction(icon, name, this);
+       action->setToolTip(tooltip);
+       action->setStatusTip(statustip);
+       QList<QKeySequence> keyList;
+       keyList.append(key1);
+       keyList.append(key2);
+       action->setShortcuts(keyList);
+       action->setCheckable(checkable);
+
+       return action;
+}
+
+
+void MainWin::closeEvent(QCloseEvent * event)
+{
+       QSettings settings("Underground Software", "WOZ Maker");
+       settings.setValue("pos", pos());
+       settings.setValue("size", size());
+       settings.setValue("lastDir", lastDir);
+
+       event->accept();
+}
+
+
+void MainWin::HandleLoadFile(void)
+{
+       QString filename = QFileDialog::getOpenFileName(this, tr("Open A2R"), lastDir, tr("A2R Disk Image Files (*.a2r)"));
+
+       if (filename.isEmpty())
+               return;
+
+       lastDir = QFileInfo(filename).path();
+
+       if (!LoadA2R(filename))
+               return;
+
+       Global::trackNum = 0;
+       mainWidget->wfWidget->HandleUpdate();
+       mainWidget->nibbleWidget->Update();
+       mainWidget->diskWidget->DrawDisk();
+       infoWidget->ShowInfo();
+       navWidget->ShowInfo();
+       setWindowTitle(QString("WOZ Maker - %1").arg(QFileInfo(filename).baseName()));
+}
+
+
+void MainWin::AboutWozMaker(void)
+{
+       QMessageBox::about(this, tr("About WOZ Maker"), tr("WOZ Maker v1.0.0\n\nWritten by James Hammons\n\nCopyright (C) 2018 Underground Software"));
+}
+
+
+bool MainWin::LoadA2R(const QString filename)
+{
+/*
+Really, this crap should go into fileio.cpp.  !!! FIX !!!
+*/
+       static uint8_t a2rHdr[8] = { 0x41, 0x32, 0x52, 0x32, 0xFF, 0x0A, 0x0D, 0x0A };
+       static uint8_t a2rHdr1[8] = { 0x41, 0x32, 0x52, 0x31, 0xFF, 0x0A, 0x0D, 0x0A };
+
+       if (Global::a2r != NULL)
+               free(Global::a2r);
+
+       Global::a2r = (A2R *)ReadFile(filename.toUtf8().data(), &Global::a2rSize);
+
+       if (Global::a2r == NULL)
+               return false;
+
+       // Sanity check, to see if what we asked for is what we got
+       if (memcmp(Global::a2r->magic1, a2rHdr, 8) != 0)
+       {
+               // It's not a v2 A2R file, maybe it's v1?
+               if (memcmp(Global::a2r->magic1, a2rHdr1, 8) == 0)
+               {
+                       // Bytes 8-F are usually: 01 00 8D 00 A5 01 00 00
+                       // First, allocate mem to copy the old version to the new:
+                       uint8_t * oldfile = (uint8_t *)Global::a2r;
+                       uint8_t * newfile = (uint8_t *)malloc(Global::a2rSize + 36);
+                       memcpy(newfile + 52, oldfile + 16, Global::a2rSize - 16);
+
+                       // Make sure creator is set correctly (v1 doesn't have it)
+                       memset(Global::a2r->creator, 0x20, 32);
+
+                       // Swap in the new file, free the old one
+                       free(Global::a2r);
+                       Global::a2r = (A2R *)newfile;
+                       Global::a2rSize += 36;  // Add in the size of the INFO chunk
+
+                       // Fix up stuff that's different between v1 and v2
+//printf("A2R Size: %08X\n", Global::a2rSize);
+//printf("A2R Stream Size: %08X (preswap)\n", Global::a2r->strmSize);
+                       SwapBytes32((uint8_t *)&Global::a2r->strmSize);
+//printf("A2R Stream Size: %08X (postswap)\n", Global::a2r->strmSize);
+                       uint32_t dataSize = Uint32LE(Global::a2r->strmSize);
+                       uint32_t pos = 0;
+
+                       while (pos < dataSize)
+                       {
+                               A2RStream * stream = (A2RStream *)(&Global::a2r->data[pos]);
+
+                               if (stream->location == 0xFF)
+                                       break;
+
+                               SwapBytes32(stream->dataLength);
+                               SwapBytes32(stream->estLoopPoint);
+                               pos += 10 + Uint32LE(stream->dataLength);
+                       }
+
+                       // Change INFO to META & fix size (if any, dunno if it's optional)
+                       if (Global::a2rSize > (60 + dataSize))
+                       {
+                               memcpy(&Global::a2r->data[dataSize], "META", 4);
+                               SwapBytes32(&Global::a2r->data[dataSize + 4]);
+                       }
+               }
+               else
+               {
+                       free(Global::a2r);
+                       Global::a2r = NULL;
+
+                       QMessageBox::critical(this, "Bad A2R file", "It may have an .a2r extension, but it isn't a valid A2R file.");
+
+                       return false;
+               }
+       }
+
+       // Setup individual stream pointers
+       Global::numStreams = 0;
+       uint8_t * streamPtr = Global::a2r->data;
+
+       while ((*streamPtr != 0xFF) && (Global::numStreams < 800))
+       {
+               Global::stream[Global::numStreams] = (A2RStream *)streamPtr;
+               streamPtr += 10 + Uint32LE(Global::stream[Global::numStreams]->dataLength);
+               Global::numStreams++;
+       }
+
+       // Metadata check
+       Global::metadata = NULL;
+
+       if (Global::a2rSize > (60 + Uint32LE(Global::a2r->strmSize)))
+       {
+               Global::metadata = (A2RMetadata *)((uint8_t *)Global::a2r + (60 + Uint32LE(Global::a2r->strmSize)));
+
+               // Make sure it's plausible metadata
+               if (memcmp(Global::metadata->metaTag, "META", 4) != 0)
+                       Global::metadata = NULL;
+       }
+
+       // Unpack TMNG & XTMG streams to simplify analysis
+       for(uint32_t i=0; i<Global::numStreams; i++)
+       {
+               Global::waveLen[i] = 0;
+
+               // Don't bother with BITS captures
+               if (Global::stream[i]->captureType == 2)
+                       continue;
+
+               // We skip the first timing byte because it can't tell you what the actual time was when the pulse was seen--it's the time between when the *capture* started and the pulse was seen, not the time between the previous pulse and this one!  So that first one is discarded since it's worse than useless; it's misleading.
+               for(uint32_t j=1; j<Uint32LE(Global::stream[i]->dataLength); j++)
+               {
+                       uint32_t a = Global::stream[i]->data[j];
+
+                       while ((Global::stream[i]->data[j] == 0xFF) || (a < 24))
+                       {
+                               j++;
+                               a += Global::stream[i]->data[j];
+                       }
+
+                       Global::wave[i][Global::waveLen[i]] = a;
+                       Global::waveLen[i]++;
+               }
+       }
+
+//ISO-8061 date format
+#if 0
+       char buf[200];
+       time_t t = time(NULL);
+       tm * tmp = gmtime(&t);
+       strftime(buf, sizeof(buf), "%FT%TZ", tmp);
+       printf("Time is: %s\n", buf);
+#endif
+
+       return true;
+}
+
diff --git a/src/mainwin.h b/src/mainwin.h
new file mode 100644 (file)
index 0000000..3b81ab2
--- /dev/null
@@ -0,0 +1,55 @@
+#ifndef __MAINWIN_H__
+#define __MAINWIN_H__
+
+#include <QtWidgets>
+
+class MainWidget;
+class InfoWidget;
+class NavWidget;
+
+class MainWin: public QMainWindow
+{
+       Q_OBJECT
+
+       public:
+               MainWin();
+               ~MainWin();
+
+       private:
+               void ResetGame(void);
+
+       protected:
+               QAction * CreateAction(QString name, QString tooltip, QString statustip,
+                       QIcon icon, QKeySequence key, bool checkable = false);
+               QAction * CreateAction(QString name, QString tooltip, QString statustip,
+                       QIcon icon, QKeySequence key1, QKeySequence key2, bool checkable = false);
+
+       protected slots:
+               void closeEvent(QCloseEvent * event);
+               void HandleLoadFile(void);
+
+               void AboutWozMaker(void);
+               bool LoadA2R(const QString);
+
+       private:
+               MainWidget * mainWidget;
+               InfoWidget * infoWidget;
+               NavWidget * navWidget;
+               QAction * loadFile;
+
+               QAction * newGame;
+               QAction * undoAction;
+
+               QAction * gameOptions;
+               QAction * gameStats;
+
+               QAction * appExit;
+               QAction * appAbout;
+               QAction * resetLevel;
+               QAction * skipLevel;
+
+               QString lastDir;
+};
+
+#endif // __MAINWIN_H__
+
diff --git a/src/navwidget.cpp b/src/navwidget.cpp
new file mode 100644 (file)
index 0000000..2e8e26a
--- /dev/null
@@ -0,0 +1,251 @@
+//
+// navwidget.cpp: A2R disk image navigation widget
+//
+// Part of the WOZ Maker Project
+// by James Hammons
+// (C) 2018 Underground Software
+// See the README and GPLv3 files for licensing and warranty information
+//
+
+#include "navwidget.h"
+#include "fileio.h"
+#include "global.h"
+
+
+NavWidget::NavWidget(void): QWidget()
+{
+       label = new QLabel;
+
+       QToolButton * pb1 = new QToolButton;
+       QToolButton * pb2 = new QToolButton;
+       QToolButton * pb3 = new QToolButton;
+       QToolButton * pb4 = new QToolButton;
+       QToolButton * pb5 = new QToolButton;
+       QToolButton * pb6 = new QToolButton;
+       QToolButton * pb7 = new QToolButton;
+       QToolButton * pb8 = new QToolButton;
+
+       QSpinBox * sb1 = new QSpinBox;
+       QSpinBox * sb2 = new QSpinBox;
+       QSpinBox * sb3 = new QSpinBox;
+       QSpinBox * sb4 = new QSpinBox;
+       QSpinBox * sb5 = new QSpinBox;
+
+       QSpinBox * sb6 = new QSpinBox;
+/*     QSpinBox * sb6 = new QSpinBox;
+       QSpinBox * sb7 = new QSpinBox;
+       QSpinBox * sb8 = new QSpinBox;
+       QSpinBox * sb9 = new QSpinBox;
+       QSpinBox * sb10 = new QSpinBox;//*/
+#if 0
+       pb1->setIcon(QIcon(":/res/layer-add.png"));
+       pb2->setIcon(QIcon(":/res/layer-delete.png"));
+       pb3->setIcon(QIcon(":/res/layer-edit.png"));
+       pb4->setIcon(QIcon(":/res/block-import.png"));
+#endif
+       pb1->setText("-");
+       pb2->setText("+");
+       pb3->setText("Sync");
+       pb4->setText("<<");
+       pb5->setText("Man. Sync");
+       pb6->setText("0 All");
+       pb7->setText("Synth");
+       pb8->setText("Synth2");
+
+       pb1->setToolTip(tr("Previous track"));
+       pb2->setToolTip(tr("Next track"));
+       pb3->setToolTip(tr("Init sync"));
+       pb4->setToolTip(tr("Step back"));
+       pb5->setToolTip(tr("Manual sync"));
+       pb6->setToolTip(tr("Reset to zero"));
+       pb7->setToolTip(tr("Synthesize waveform"));
+       pb8->setToolTip(tr("Synthesize waveform 2"));
+
+       sb1->setMaximum(80000);
+       sb2->setMaximum(80000);
+       sb3->setMaximum(80000);
+       sb4->setMaximum(80000);
+       sb5->setMaximum(80000);
+
+       sb6->setMaximum(80000);
+/*     sb6->setMaximum(2000000);
+       sb7->setMaximum(2000000);
+       sb8->setMaximum(2000000);
+       sb9->setMaximum(2000000);
+       sb10->setMaximum(2000000);//*/
+
+       QHBoxLayout * hbox1 = new QHBoxLayout;
+       QHBoxLayout * hbox2 = new QHBoxLayout;
+       QHBoxLayout * hbox3 = new QHBoxLayout;
+       QHBoxLayout * hbox4 = new QHBoxLayout;
+       hbox1->addWidget(pb1);
+       hbox1->addWidget(pb2);
+       hbox1->addWidget(pb3);
+       hbox1->addWidget(pb4);
+       hbox1->addStretch();
+
+       hbox2->addWidget(pb5);
+       hbox2->addWidget(pb6);
+       hbox2->addWidget(pb7);
+       hbox2->addStretch();
+
+       hbox3->addWidget(sb1);
+       hbox3->addWidget(sb2);
+       hbox3->addWidget(sb3);
+       hbox3->addWidget(sb4);
+       hbox3->addWidget(sb5);
+       hbox3->addStretch();
+
+       hbox4->addWidget(sb6);
+       hbox4->addWidget(pb8);
+/*     hbox4->addWidget(sb6);
+       hbox4->addWidget(sb7);
+       hbox4->addWidget(sb8);
+       hbox4->addWidget(sb9);
+       hbox4->addWidget(sb10);
+       hbox4->addStretch();//*/
+
+       QVBoxLayout * mainLayout = new QVBoxLayout;
+       mainLayout->addWidget(label);
+       mainLayout->addStretch();
+       mainLayout->addLayout(hbox4);
+       mainLayout->addLayout(hbox3);
+       mainLayout->addLayout(hbox1);
+       mainLayout->addLayout(hbox2);
+
+       setLayout(mainLayout);
+
+       connect(pb1, SIGNAL(clicked()), this, SLOT(HandlePrevTrack()));
+       connect(pb2, SIGNAL(clicked()), this, SLOT(HandleNextTrack()));
+       connect(pb3, SIGNAL(clicked()), this, SLOT(HandleInitSync()));
+       connect(pb4, SIGNAL(clicked()), this, SLOT(HandleStepBack()));
+       connect(pb5, SIGNAL(clicked()), this, SLOT(HandleManualSync()));
+       connect(pb6, SIGNAL(clicked()), this, SLOT(HandleZeroAll()));
+       connect(pb7, SIGNAL(clicked()), this, SLOT(HandleSynthesize()));
+       connect(pb8, SIGNAL(clicked()), this, SLOT(HandleSynthesize2()));
+
+       connect(sb1, SIGNAL(valueChanged(int)), this, SLOT(HandleSync1(int)));
+       connect(sb2, SIGNAL(valueChanged(int)), this, SLOT(HandleSync2(int)));
+       connect(sb3, SIGNAL(valueChanged(int)), this, SLOT(HandleSync3(int)));
+       connect(sb4, SIGNAL(valueChanged(int)), this, SLOT(HandleSync4(int)));
+       connect(sb5, SIGNAL(valueChanged(int)), this, SLOT(HandleSync5(int)));
+
+       connect(sb6, SIGNAL(valueChanged(int)), this, SLOT(HandleWaveSync(int)));
+/*     connect(sb6, SIGNAL(valueChanged(int)), this, SLOT(HandleRatio1(int)));
+       connect(sb7, SIGNAL(valueChanged(int)), this, SLOT(HandleRatio2(int)));
+       connect(sb8, SIGNAL(valueChanged(int)), this, SLOT(HandleRatio3(int)));
+       connect(sb9, SIGNAL(valueChanged(int)), this, SLOT(HandleRatio4(int)));
+       connect(sb10, SIGNAL(valueChanged(int)), this, SLOT(HandleRatio5(int)));//*/
+}
+
+
+NavWidget::~NavWidget()
+{
+}
+
+
+void NavWidget::ShowInfo(void)
+{
+       QString s;
+       s += QString("Track No.: %1<br>").arg((double)Global::trackNum / 4.0, 0, 'f', 2);
+       s += QString("Stream No.: %1<br>").arg(Global::streamNum);
+       s += QString("Nibbles: %1<br>").arg(Global::nibbleCount);
+       s += QString("Bloops: %1<br>").arg(Global::bloops);
+
+       label->setText(s);
+}
+
+
+void NavWidget::HandlePrevTrack(void)
+{
+       if (Global::trackNum == 0)
+               return;
+
+       Global::trackNum--;
+       ShowInfo();
+       emit(UpdateWaveform());
+}
+
+
+void NavWidget::HandleNextTrack(void)
+{
+       if (Global::trackNum == (35 * 4))
+               return;
+
+       Global::trackNum++;
+       ShowInfo();
+       emit(UpdateWaveform());
+}
+
+
+void NavWidget::HandleInitSync(void)
+{
+       emit(InitSync());
+}
+
+
+void NavWidget::HandleStepBack(void)
+{
+       emit(StepBack());
+}
+
+
+void NavWidget::HandleManualSync(void)
+{
+       emit(ManualSync());
+}
+
+
+void NavWidget::HandleZeroAll(void)
+{
+       emit(ZeroAll());
+}
+
+
+void NavWidget::HandleSynthesize(void)
+{
+       emit(Synthesize());
+}
+
+
+void NavWidget::HandleSynthesize2(void)
+{
+       emit(Synthesize2());
+}
+
+
+void NavWidget::HandleSync1(int num)
+{
+       emit(Sync(0, num));
+}
+
+
+void NavWidget::HandleSync2(int num)
+{
+       emit(Sync(1, num));
+}
+
+
+void NavWidget::HandleSync3(int num)
+{
+       emit(Sync(2, num));
+}
+
+
+void NavWidget::HandleSync4(int num)
+{
+       emit(Sync(3, num));
+}
+
+
+void NavWidget::HandleSync5(int num)
+{
+       emit(Sync(4, num));
+}
+
+
+void NavWidget::HandleWaveSync(int num)
+{
+       emit(WaveSync(num));
+}
+
diff --git a/src/navwidget.h b/src/navwidget.h
new file mode 100644 (file)
index 0000000..e95ed15
--- /dev/null
@@ -0,0 +1,48 @@
+#ifndef __NAVWIDGET_H__
+#define __NAVWIDGET_H__
+
+#include <QtWidgets>
+
+class NavWidget: public QWidget
+{
+       Q_OBJECT
+
+       public:
+               NavWidget(void);
+               ~NavWidget();
+
+       signals:
+               void UpdateWaveform(void);
+               void InitSync(void);
+               void StepBack(void);
+               void ManualSync(void);
+               void ZeroAll(void);
+               void Synthesize(void);
+               void Synthesize2(void);
+               void Sync(int, int);
+               void WaveSync(int);
+               void Ratio(int, int);
+
+       public slots:
+               void ShowInfo(void);
+               void HandlePrevTrack(void);
+               void HandleNextTrack(void);
+               void HandleInitSync(void);
+               void HandleStepBack(void);
+               void HandleManualSync(void);
+               void HandleZeroAll(void);
+               void HandleSynthesize(void);
+               void HandleSynthesize2(void);
+               void HandleSync1(int);
+               void HandleSync2(int);
+               void HandleSync3(int);
+               void HandleSync4(int);
+               void HandleSync5(int);
+               void HandleWaveSync(int);
+
+       private:
+               QLabel * label;
+};
+
+#endif // __NAVWIDGET_H__
+
diff --git a/src/nibblewidget.cpp b/src/nibblewidget.cpp
new file mode 100644 (file)
index 0000000..1c5a2e3
--- /dev/null
@@ -0,0 +1,277 @@
+//
+// nibblewidget.cpp: Track waveform nibble display widget
+//
+// Part of the WOZ Maker project
+// by James Hammons
+// (C) 2018 Underground Software
+//
+
+#include "nibblewidget.h"
+#include "fileio.h"
+#include "global.h"
+
+
+NibbleWidget::NibbleWidget(QWidget * parent/*= 0*/): QWidget(parent)
+{
+       // Is this even needed?
+       setGeometry(QRect(0, 0, 20, 20));
+}
+
+
+NibbleWidget::~NibbleWidget(void)
+{
+}
+
+
+void NibbleWidget::Update(void)
+{
+       DecodeWaveform();
+       DecodeBitstream();
+
+       setMinimumWidth(52 * fWidth);
+//     setMaximumWidth(52 * fWidth);
+       setMinimumHeight(((Global::nibbleCount + 51) / 52) * fHeight);
+       setMaximumHeight(((Global::nibbleCount + 51) / 52) * fHeight);
+       update();
+}
+
+
+void NibbleWidget::DecodeWaveform(void)
+{
+       // Sanity check
+       if (Global::streamNum >= Global::numStreams)
+               return;
+
+       uint8_t * data = Global::bitStream;
+       uint32_t dataSize = Uint32LE(Global::stream[Global::streamNum]->dataLength);
+       uint8_t * sdata = Global::stream[Global::streamNum]->data;
+       uint32_t & bits = Global::bitStreamLength;
+       bits = 0;
+
+       // Prime the pump
+       data[bits++] = 1;
+
+       for(uint32_t i=1; i<dataSize; i++)
+       {
+               uint32_t timeToNext = sdata[i];
+
+               if (sdata[i] == 0xFF)
+               {
+                       while (sdata[i++] == 0xFF)
+                               timeToNext += sdata[i];
+               }
+
+               if ((sdata[i] > 24))
+               {
+                       if ((timeToNext >= 24) && (timeToNext <= 49))
+                       {
+                               data[bits++] = 1;
+                       }
+                       else if ((timeToNext >= 50) && (timeToNext <= 80))
+                       {
+                               data[bits++] = 0;
+                               data[bits++] = 1;
+                       }
+                       else if ((timeToNext >= 81) && (timeToNext <= 112))
+                       {
+                               data[bits++] = 0;
+                               data[bits++] = 0;
+                               data[bits++] = 1;
+                       }
+                       else if ((timeToNext >= 113) && (timeToNext <= 137))
+                       {
+                               data[bits++] = 0;
+                               data[bits++] = 0;
+                               data[bits++] = 0;
+                               data[bits++] = 1;
+                       }
+                       else
+                       {
+                               // Handle zeros here...
+                               while (timeToNext > 32)
+                               {
+                                       data[bits++] = 0;
+                                       timeToNext -= 32;
+                               }
+
+                               data[bits++] = 1;
+                       }
+               }
+       }
+}
+
+
+void NibbleWidget::DecodeBitstream(void)
+{
+       uint8_t zeroBits3[6] = { 0xE0, 0x70, 0x38, 0x1C, 0x0E, 0x07 };
+       uint8_t * data = Global::bitStream;
+
+       // Sanity check
+       if (data == NULL)
+               return;
+
+       uint32_t dataSize = Global::bitStreamLength;
+       uint32_t pos = 0;
+       uint8_t byte = 0;
+       Global::nibbleCount = 0;
+       memset(nibble, 0, sizeof(uint16_t) * 10000);
+
+       while (pos < dataSize)
+       {
+               uint8_t bit = data[pos];
+
+               if (byte & 0x80)
+               {
+                       if (!bit)
+                               nibble[Global::nibbleCount]++;
+                       else
+                       {
+                               // Check to see if there are illegal bit patterns in the
+                               // decoded byte
+                               for(uint8_t i=0; i<6; i++)
+                               {
+                                       if ((byte & zeroBits3[i]) == 0)
+                                       {
+                                               nibble[Global::nibbleCount] |= 0x0080;
+                                               break;
+                                       }
+                               }
+
+                               nibble[Global::nibbleCount++] |= byte << 8;
+                               byte = 1;
+                       }
+               }
+               else
+                       byte = (byte << 1) | (bit ? 1 : 0);
+
+               pos++;
+       }
+}
+
+
+void NibbleWidget::paintEvent(QPaintEvent * /*event*/)
+{
+       QPainter painter(this);
+       painter.setRenderHint(QPainter::Antialiasing);
+
+//     QFont font("Monospace"); // ugly
+//     QFont font("DejaVu Sans Mono"); // ugly
+       QFont font("Hack");
+       font.setPixelSize(14.5);
+       font.setWeight(QFont::Black);
+       font.setHintingPreference(QFont::PreferFullHinting);
+       font.setStyleHint(QFont::Monospace);
+       painter.setFont(font);
+
+       for(uint32_t y=0; y<(Global::nibbleCount+51)/52; y++)
+       {
+               for(uint32_t x=0; x<52; x++)
+               {
+                       if (((y * 52) + x) >= Global::nibbleCount)
+                               break;
+
+                       QRectF r(x * fWidth, y * fHeight, fWidth, fHeight);
+                       uint8_t trailingZeroes = nibble[(y * 52) + x] & 0x7F;
+                       uint8_t badBitPattern = nibble[(y * 52) + x] & 0x80;
+
+                       if (trailingZeroes)
+                               painter.fillRect(r, QColor(0xBF, 0xE3, 0xEF, 0xFF));
+                       else
+                               painter.fillRect(r, Qt::white);
+
+                       if (badBitPattern)
+                               painter.setPen(Qt::red);
+
+                       painter.drawText(r.translated(0.0, 2.0), Qt::AlignCenter, QString("%1").arg((ushort)(nibble[(y * 52) + x] >> 8), 2, 16, QChar('0')).toUpper());
+                       painter.setPen(Qt::black);
+
+                       if (trailingZeroes == 1)
+                       {
+                               painter.drawEllipse(QPointF(r.x() + ((float)fWidth / 2.0f), r.y() + 5.0f), 2.0f, 2.0f);
+                       }
+                       else if (trailingZeroes == 2)
+                       {
+                               painter.drawEllipse(QPointF(r.x() + ((float)fWidth / 2.0f) - 4.0f, r.y() + 5.0f), 2.0f, 2.0f);
+                               painter.drawEllipse(QPointF(r.x() + ((float)fWidth / 2.0f) + 4.0f, r.y() + 5.0f), 2.0f, 2.0f);
+                       }
+                       else if (trailingZeroes >= 3)
+                       {
+                               painter.drawEllipse(QPointF(r.x() + ((float)fWidth / 2.0f), r.y() + 5.0f), 2.0f, 2.0f);
+                               painter.drawEllipse(QPointF(r.x() + ((float)fWidth / 2.0f) - 6.0f, r.y() + 5.0f), 2.0f, 2.0f);
+                               painter.drawEllipse(QPointF(r.x() + ((float)fWidth / 2.0f) + 6.0f, r.y() + 5.0f), 2.0f, 2.0f);
+                       }
+               }
+       }
+}
+
+
+void NibbleWidget::mousePressEvent(QMouseEvent * event)
+{
+       if (event->button() == Qt::LeftButton)
+       {
+               event->accept();
+       }
+}
+
+
+void NibbleWidget::mouseMoveEvent(QMouseEvent * event)
+{
+       if (event->buttons() & Qt::LeftButton)
+       {
+               event->accept();
+       }
+}
+
+
+void NibbleWidget::mouseReleaseEvent(QMouseEvent * event)
+{
+       if (event->button() == Qt::LeftButton)
+       {
+               event->accept();
+       }
+}
+
+
+void NibbleWidget::mouseDoubleClickEvent(QMouseEvent * event)
+{
+       if (event->button() == Qt::LeftButton)
+       {
+               event->accept();
+       }
+}
+
+
+void NibbleWidget::keyPressEvent(QKeyEvent * event)
+{
+       int key = event->key();
+
+       if (key == Qt::Key_Up)
+       {
+       }
+       else if (key == Qt::Key_Down)
+       {
+       }
+       else if (key == Qt::Key_Left)
+       {
+       }
+       else if (key == Qt::Key_Right)
+       {
+       }
+       else
+               return;
+
+       // Only update if a key we recognize has been pressed!
+       update();
+}
+
+
+void NibbleWidget::keyReleaseEvent(QKeyEvent * /*event*/)
+{
+}
+
+
+void NibbleWidget::resizeEvent(QResizeEvent * /*event*/)
+{
+//     ResizeGrid();
+}
+
diff --git a/src/nibblewidget.h b/src/nibblewidget.h
new file mode 100644 (file)
index 0000000..66f2426
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef __NIBBLEWIDGET_H__
+#define __NIBBLEWIDGET_H__
+
+#include <QtWidgets>
+#include <stdint.h>
+
+class NibbleWidget: public QWidget
+{
+       Q_OBJECT
+
+       public:
+               NibbleWidget(QWidget * parent = 0);
+               ~NibbleWidget();
+
+       protected:
+               void paintEvent(QPaintEvent * event);
+               void mousePressEvent(QMouseEvent * event);
+               void mouseMoveEvent(QMouseEvent * event);
+               void mouseReleaseEvent(QMouseEvent * event);
+               void mouseDoubleClickEvent(QMouseEvent * event);
+               void keyPressEvent(QKeyEvent * event);
+               void keyReleaseEvent(QKeyEvent * event);
+               void resizeEvent(QResizeEvent * event);
+
+//     signals:
+//             void GameWasWon(void);
+
+//     public slots:
+//             void HandlePlayGameFromEditor(Level *);
+
+       public:
+               void Update(void);
+
+       private:
+               void DecodeWaveform(void);
+               void DecodeBitstream(void);
+
+       private:
+               uint16_t nibble[10000];
+
+       public:
+               static const uint32_t fWidth = 24, fHeight = 28;
+};
+
+#endif // __NIBBLEWIDGET_H__
+
diff --git a/src/tmpwindow.cpp b/src/tmpwindow.cpp
new file mode 100644 (file)
index 0000000..979a1c1
--- /dev/null
@@ -0,0 +1,90 @@
+//
+// tmpwindow.cpp: Disk structure window
+//
+// Part of the WOZ Maker project
+// by James Hammons
+// (C) 2018 Underground Software
+//
+
+#include "tmpwindow.h"
+#include "fileio.h"
+#include "global.h"
+
+
+TmpWindow::TmpWindow(QWidget * parent/*= 0*/): QWidget(parent, Qt::Window)
+{
+       setGeometry(QRect(0, 0, 1024, 1024));
+       setMinimumWidth(1024);
+       setMinimumHeight(1024);
+       setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+}
+
+
+TmpWindow::~TmpWindow(void)
+{
+}
+
+
+void TmpWindow::paintEvent(QPaintEvent * /*event*/)
+{
+       QPainter painter(this);
+       painter.setRenderHint(QPainter::Antialiasing);
+
+       QPen dkGreyPen(QColor(0x3A, 0x3B, 0x3A, 0xFF), 1.0, Qt::SolidLine);
+       QBrush dkGreyBrush(QColor(0x3A, 0x3B, 0x3A, 0xFF));
+
+       // Draw empty disk
+       painter.setPen(dkGreyPen);
+       painter.setBrush(dkGreyBrush);
+       painter.drawEllipse(0, 0, 1024, 1024);
+       painter.setPen(Qt::white);
+       painter.setBrush(Qt::white);
+       painter.drawEllipse(388, 388, 248, 248);
+
+       // Draw disk track data
+       uint8_t lastLocation = 0xFF;
+       uint32_t x = 4, y = 4, w = 1024 - (2 * 4);
+
+       for(uint32_t str=0; str<Global::numStreams; str++)
+       {
+               if (Global::stream[str]->location != lastLocation)
+               {
+                       uint32_t splicePoint = Uint32LE(Global::stream[str]->estLoopPoint);
+                       float angleTime = (float)splicePoint / (5760.0f / 2.0f);
+                       uint32_t pos = 0;
+                       float strTime = 0;
+                       float curTime = angleTime;
+
+                       for(uint32_t i=0; i<5760; i+=2)
+                       {
+                               float ones = 0;
+
+                               while (strTime < curTime)
+                               {
+                                       while (Global::stream[str]->data[pos] == 0xFF)
+                                               strTime += Global::stream[str]->data[pos++];
+
+                                       strTime += Global::stream[str]->data[pos++];
+                                       ones += 1.0f;
+                               }
+
+                               uint32_t color = ((ones * 32.0f) / angleTime) * 255.0f;
+
+                               if (color > 255)
+                                       color = 255;
+
+                               painter.setPen(QPen(QColor(color, color, color, 0xFF), 1.0, Qt::SolidLine));
+                               painter.drawArc(x, y, w, w, -i, 2);
+                               painter.drawArc(x+1, y+1, w-2, w-2, -i, 2);
+
+                               curTime += angleTime;
+                       }
+
+                       x += 2;
+                       y += 2;
+                       w -= 4;
+                       lastLocation = Global::stream[str]->location;
+               }
+       }
+}
+
diff --git a/src/tmpwindow.h b/src/tmpwindow.h
new file mode 100644 (file)
index 0000000..391a864
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef __TMPWINDOW_H__
+#define __TMPWINDOW_H__
+
+#include <QtWidgets>
+
+class TmpWindow: public QWidget
+{
+       Q_OBJECT
+
+       public:
+               TmpWindow(QWidget * parent = 0);
+               ~TmpWindow();
+
+       protected:
+               void paintEvent(QPaintEvent * event);
+};
+
+#endif // __TMPWINDOW_H__
+
diff --git a/src/waveformwidget.cpp b/src/waveformwidget.cpp
new file mode 100644 (file)
index 0000000..e3ca3bf
--- /dev/null
@@ -0,0 +1,686 @@
+//
+// waveformwidget.cpp: Track waveform window widget
+//
+// Part of the WOZ Maker project
+// by James Hammons
+// (C) 2018 Underground Software
+//
+
+#include "waveformwidget.h"
+#include <math.h>
+#include "dsp.h"
+#include "fileio.h"
+#include "global.h"
+
+
+// Local variables
+static uint32_t slip[9];
+static bool foundBad = false;
+
+
+WaveformWidget::WaveformWidget(QWidget * parent/*= 0*/): QWidget(parent)
+{
+#if 0
+       setGeometry(QRect(0, 0, 20, 240));
+       setMinimumHeight(240);
+       setMaximumHeight(240);
+#else
+       setGeometry(QRect(0, 0, 20, 320));
+       setMinimumHeight(320);
+       setMaximumHeight(320);
+#endif
+}
+
+
+WaveformWidget::~WaveformWidget(void)
+{
+}
+
+
+void WaveformWidget::HandleUpdate(void)
+{
+       // Set up vars that only change when the track changes...
+       uint32_t total = 0;
+       Global::streamCount = 0;
+       memset(slip, 0, sizeof(slip));
+       uint32_t xmax = 0;
+
+       // Find all non-BITS stream captures for this quarter-track
+       for(uint32_t i=0; i<Global::numStreams; i++)
+       {
+               if ((Global::stream[i]->location != Global::trackNum)
+                       || (Global::stream[i]->captureType == 2))
+                       continue;
+
+               uint32_t timeToNext = 0;
+               uint32_t trackBytes = Uint32LE(Global::stream[i]->dataLength);
+
+               // Set up stream vars for this track
+               Global::streamData[Global::streamCount] = Global::stream[i]->data;
+               Global::streamLen[Global::streamCount++] = trackBytes;
+
+               // Save the stream number for later reference
+               sNum[total++] = i;
+
+               // Count time for this stream (skipping 0, because it doesn't count)
+               for(uint32_t j=1; j<trackBytes; j++)
+                       timeToNext += Global::stream[i]->data[j];
+
+               if ((timeToNext / 2) > xmax)
+                       xmax = timeToNext / 2;
+       }
+
+       Global::swLen = 0;
+
+       if (Global::streamCount > 1)
+       {
+               // Try aligning streams algorithmically...
+//             FindSyncForStreams(slip, Global::streamCount);
+               FindInitialSyncForStreams2(slip, Global::streamCount);
+//             InitialSync(slip, Global::streamCount);
+//             AttemptToFindStart(slip, Global::streamCount);
+               Global::swLen = Synthesize2(slip, Global::streamCount, Global::synthWave, Global::swAmplitude);
+       }
+
+for(uint32_t i=0; i<Global::streamCount; i++)
+{      printf("Sync point %d: %d\n", sNum[i], slip[i]); }
+
+#if 0
+printf("Lookahead for track %.2f: %d\n", (float)Global::trackNum / 4.0f, Lookahead(slip, Global::streamCount, +1));
+#endif
+
+       // And finally, update the display
+       setMinimumWidth(xmax);
+       setMaximumWidth(xmax);
+       update();
+}
+
+
+//#define PACKED
+void WaveformWidget::HandleInitSync(void)
+{
+#ifdef PACKED
+       FindInitialSyncForStreams(slip, Global::streamCount);
+#endif
+       foundBad = false;
+       update();
+
+#if 1
+       printf("------------------------------\nInitial sync (%.2f): ", (float)Global::trackNum / 4.0f);
+       for(uint32_t i=0; i<Global::streamCount; i++)
+               printf("<%d> ", slip[i]);
+       printf("\n\n");
+#endif
+}
+
+
+void WaveformWidget::HandleStepBack(void)
+{
+#ifdef PACKED
+       static double a[10];
+#endif
+       uint32_t minIdx = SmallestIndex(slip, Global::streamCount);
+
+       if (slip[minIdx] == 0)
+               return;
+
+       if (!foundBad)
+       {
+#ifdef PACKED
+               StepBackUntilBad(slip, a, Global::streamCount);
+#endif
+               foundBad = true;
+
+               for(uint32_t i=0; i<Global::streamCount; i++)
+                       printf("<%d> ", slip[i]);
+               printf("\n");
+       }
+       else
+       {
+#ifdef PACKED
+               foundBad = StepBackThruBad(slip, a, Global::streamCount);
+#endif
+       }
+
+       update();
+}
+
+
+void WaveformWidget::HandleManualSync(void)
+{
+#ifdef PACKED
+       double a[10];
+#endif
+       foundBad = false;
+#ifdef PACKED
+       StepBack(slip, a, Global::streamCount);
+#endif
+       update();
+
+#if 1
+       printf("------------------------------\nManual sync (%.2f): ", (float)Global::trackNum / 4.0f);
+       for(uint32_t i=0; i<Global::streamCount; i++)
+               printf("<%d> ", slip[i]);
+       printf("\n\n");
+#endif
+}
+
+
+void WaveformWidget::HandleZeroAll(void)
+{
+       memset(slip, 0, sizeof(slip));
+       update();
+}
+
+
+void WaveformWidget::HandleSynthesize(void)
+{
+//     Global::swLen = Synthesize(slip, Global::streamCount, Global::synthWave, Global::swAmplitude);
+       Global::swLen = Synthesize2(slip, Global::streamCount, Global::synthWave, Global::swAmplitude);
+       emit(UpdateInfo());
+       update();
+}
+
+
+void WaveformWidget::HandleSynthesize2(void)
+{
+       SynthesizeTrack(Global::trackNum);
+//     emit(UpdateInfo());
+       update();
+}
+
+
+void WaveformWidget::HandleSync(int stream, int num)
+{
+       if (stream > 9)
+               return;
+
+       slip[stream] = num;
+       update();
+}
+
+
+void WaveformWidget::HandleWaveSync(int num)
+{
+       Global::waveSync = num;
+       update();
+}
+
+
+void WaveformWidget::HandleRatio(int /*stream*/, int /*num*/)
+{
+//     if (stream > 9)
+//             return;
+
+//     ratio[stream] = (double)num / 1600000.0;
+       update();
+}
+
+
+/*
+Now we have SynthesizeTrack(trackNo), so we can display the results of that here--including the loop point if we found one...
+
+Now our analysis thread calcs it for us...  One less thing to worry about!
+*/
+
+void WaveformWidget::paintEvent(QPaintEvent * event)
+{
+       if (Global::a2r == NULL)
+               return;
+
+       uint32_t xpos = event->rect().x();
+       uint32_t width = event->rect().width();
+
+       QPainter painter(this);
+       painter.setRenderHint(QPainter::Antialiasing);
+       QFont font;
+
+       font.setPixelSize(12);
+       font.setBold(true);
+       font.setStyleHint(QFont::TypeWriter);
+       painter.setFont(font);
+
+       QPen greenPen(QColor(0x66, 0x9E, 0x55, 0xFF), 2.0, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
+       QPen bluePen(QColor(0x20, 0x8F, 0xB5, 0xFF), 2.0, Qt::SolidLine);
+       QPen whitePen(Qt::white, 2.0, Qt::SolidLine);
+       QPen greyPen(QColor(0x4F, 0x49, 0x47, 0xFF), 2.0, Qt::SolidLine);
+       QPen orangePen(QColor(0xDE, 0x6A, 0x00, 0xFF), 2.0, Qt::SolidLine);
+
+//BG: 3B3632, GRN: 669E55, BLU: 208FB5, V.Lines: 4F4947
+// 12 (line + hex num), 3 space, 18 for trace, 7 after space
+// 7px padding on top, 8px on bottom
+// Nibble view is 52 x 12 bytes
+
+//     float y = 7 + 12 + 18;
+       float y = 7 + 12 + 18 + (40 * 3);
+       float drawXPos = (xpos < 8 ? 0 : xpos - 8);
+       uint32_t wfNum = 0;
+
+//printf("update: ");
+       for(uint32_t j=0; j<Global::numStreams; j++)
+       {
+               if (Global::stream[j]->location != Global::trackNum)
+                       continue;
+
+               float x = 0;
+               float lastx = 0;
+//             uint32_t trackBytes = Uint32LE(Global::stream[j]->dataLength);
+               uint32_t trackBytes = Global::waveLen[j] - slip[wfNum];
+               uint32_t estSplice = Uint32LE(Global::stream[j]->estLoopPoint);
+               uint32_t byte = 1;
+               uint32_t bytePos = 0;
+               uint32_t bitCount = 1;
+//             int32_t extra = (foundBad ? -1 : 0);
+               uint32_t offset = slip[wfNum];
+//printf("<%d> ", offset);
+
+               if ((Global::stream[j]->captureType == 1) || (Global::stream[j]->captureType == 3))
+               {
+                       for(uint32_t i=0; i<trackBytes; i++)
+                       {
+#if 0
+                               uint32_t timeToNext = Global::stream[j]->data[offset + i];
+
+                               while (Global::stream[j]->data[offset + i] == 0xFF)
+                               {
+                                       i++;
+                                       timeToNext += Global::stream[j]->data[offset + i];
+                               }
+#else
+                               uint32_t timeToNext = Global::wave[j][offset + i];
+#endif
+
+//                             if (i > 0)
+       //                              x += timeToNext / 2;
+                                       x += ((double)timeToNext / 2.0);// * ratio[wfNum];
+
+//                             if ((Global::stream[j]->data[offset + i] > 24) || (i == 0))
+                               {
+                                       if (x >= drawXPos)
+                                       {
+                                               painter.setPen(bluePen);
+
+                                               if (x >= ((estSplice / 2) /* * ratio[wfNum]*/))
+                                                       painter.setPen(Qt::magenta);
+
+                                               painter.drawLine(lastx, y, x, y);
+                                               painter.drawLine(x, y, x + 4.0, y);
+                                               painter.drawLine(x + 4.0, y, x + 4.0, y - 17.0);
+                                               painter.drawLine(x + 4.0, y - 17.0, x + 8.0, y - 17.0);
+                                               painter.drawLine(x + 8.0, y - 17.0, x + 8.0, y);
+                                               lastx = x + 8.0;
+                                       }
+
+//                                     if (i == 0)
+//                                     {
+//                                             byte = 1;
+//                                             bitCount = 1;
+//                                             bytePos = x;
+//                                     }
+//                                     else
+                                       {
+                                               if ((timeToNext >= 24) && (timeToNext <= 49))
+                                               {
+                                                       byte = (byte << 1) | 1;
+                                                       bitCount++;
+                                               }
+                                               else if ((timeToNext >= 50) && (timeToNext <= 80))
+                                               {
+                                                       byte = (byte << 2) | 1;
+                                                       bitCount += 2;
+                                               }
+                                               else if ((timeToNext >= 81) && (timeToNext <= 112))
+                                               {
+                                                       byte = (byte << 3) | 1;
+                                                       bitCount += 3;
+                                               }
+                                               else if ((timeToNext >= 113) && (timeToNext <= 137))
+                                               {
+                                                       byte = (byte << 4) | 1;
+                                                       bitCount += 4;
+                                               }
+                                               else
+                                               {
+                                                       // Handle zeros here...
+                                                       while (timeToNext > 32)
+                                                       {
+                                                               byte <<= 1;
+                                                               bitCount++;
+                                                               timeToNext -= 32;
+                                                       }
+                                               }
+                                       }
+
+                                       if (bitCount > 8)
+                                       {
+                                               while (bitCount > 15)
+                                                       bitCount -= 8;
+
+                                               uint16_t mask1[16] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF };
+                                               uint16_t mask2[16] = { 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000 };
+                                               uint8_t byteToShow = byte >> (bitCount - 8);
+                                               bitCount -= 8;
+                                               byte &= mask1[bitCount];
+                                               uint8_t zeroes = 0;
+
+                                               for(uint16_t z=bitCount; z>0; z--)
+                                               {
+                                                       if ((byte & mask2[z - 1]) == 0)
+                                                       {
+                                                               bitCount--;
+                                                               zeroes++;
+                                                       }
+                                                       else
+                                                               break;
+                                               }
+
+                                               char buf[10];
+                                               sprintf(buf, "|%02X%s", byteToShow, (zeroes == 0 ? "" : (zeroes == 1 ? "." : (zeroes == 2 ? ".." : "..."))));
+
+                                               painter.setPen(whitePen);
+                                               painter.drawText(bytePos, y - (18 + 6), buf);
+
+                                               bytePos = x;
+
+                                               if (bytePos > (xpos + width))
+                                                       break;
+                                       }
+                               }
+                       }
+               }
+               else if (Global::stream[j]->captureType == 2)
+               {
+                       // BITS capture
+/*
+x positions are 16 pix apart, ideally.  So to get the # of bits, we need to divide the width / 16.  To get the # of bytes, we then divide by 8.
+*/
+                       uint32_t bpStart = xpos / 16;
+                       x = bpStart * 16.0;
+
+                       for(uint32_t i=bpStart; i<bpStart+(width/16)+4; i++)
+                       {
+                               if (Global::stream[j]->data[i / 8] & Global::bit[i % 8])
+                               {
+                                       painter.setPen(Qt::cyan);
+                                       painter.drawLine(lastx, y, x, y);
+                                       painter.drawLine(x, y, x + 4, y);
+                                       painter.drawLine(x + 4, y, x + 4, y - 17);
+                                       painter.drawLine(x + 4, y - 17, x + 8, y - 17);
+                                       painter.drawLine(x + 8, y - 17, x + 8, y);
+                                       lastx = x + 8.0;
+                               }
+
+                               x += 16.0;
+                       }
+               }
+
+               y += 40.0;
+               wfNum++;
+       }
+//printf("\n");
+
+       if (Global::swLen == 0)
+               return;
+
+       // Reset Y coord to the top
+       y = 7 + 12 + 18;
+       float x = 0;
+       float lastx = 0;
+       uint32_t byte = 1;
+       uint32_t bytePos = x;
+       uint32_t bitCount = 1;
+       float hgt = 17.0f * 1.0f;
+
+       painter.setPen(greenPen);
+       painter.drawLine(lastx, y, x, y);
+       painter.drawLine(x, y, x + 4.0, y);
+       painter.drawLine(x + 4.0, y, x + 4.0, y - hgt);
+       painter.drawLine(x + 4.0, y - hgt, x + 8.0, y - hgt);
+       painter.drawLine(x + 8.0, y - hgt, x + 8.0, y);
+       lastx = x + 8.0;
+
+       for(uint32_t i=0; i<Global::swLen; i++)
+       {
+               uint32_t timeToNext = Global::synthWave[i];
+               hgt = 17.0 * Global::swAmplitude[i];
+               x += (double)timeToNext / 2.0;
+
+               if ((timeToNext > 0) || (i == 0))
+               {
+                       if (x >= drawXPos)
+                       {
+                               painter.setPen(greenPen);
+                               painter.drawLine(lastx, y, x, y);
+                               painter.drawLine(x, y, x + 4.0, y);
+                               painter.drawLine(x + 4.0, y, x + 4.0, y - hgt);
+                               painter.drawLine(x + 4.0, y - hgt, x + 8.0, y - hgt);
+                               painter.drawLine(x + 8.0, y - hgt, x + 8.0, y);
+                               lastx = x + 8.0;
+                       }
+
+                       if ((timeToNext >= 24) && (timeToNext <= 49))
+                       {
+                               byte = (byte << 1) | 1;
+                               bitCount++;
+                       }
+                       else if ((timeToNext >= 50) && (timeToNext <= 80))
+                       {
+                               byte = (byte << 2) | 1;
+                               bitCount += 2;
+                       }
+                       else if ((timeToNext >= 81) && (timeToNext <= 112))
+                       {
+                               byte = (byte << 3) | 1;
+                               bitCount += 3;
+                       }
+                       else if ((timeToNext >= 113) && (timeToNext <= 137))
+                       {
+                               byte = (byte << 4) | 1;
+                               bitCount += 4;
+                       }
+                       else
+                       {
+                               // Handle zeros here...
+                               while (timeToNext > 32)
+                               {
+                                       byte <<= 1;
+                                       bitCount++;
+                                       timeToNext -= 32;
+                               }
+                       }
+
+                       if (bitCount > 8)
+                       {
+                               while (bitCount > 15)
+                                       bitCount -= 8;
+
+                               uint16_t mask1[16] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF };
+                               uint16_t mask2[16] = { 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000 };
+                               uint8_t byteToShow = byte >> (bitCount - 8);
+                               bitCount -= 8;
+                               byte &= mask1[bitCount];
+                               uint8_t zeroes = 0;
+
+                               for(uint16_t z=bitCount; z>0; z--)
+                               {
+                                       if ((byte & mask2[z - 1]) == 0)
+                                       {
+                                               bitCount--;
+                                               zeroes++;
+                                       }
+                                       else
+                                               break;
+                               }
+
+                               char buf[10];
+                               sprintf(buf, "|%02X%s", byteToShow, (zeroes == 0 ? "" : (zeroes == 1 ? "." : (zeroes == 2 ? ".." : "..."))));
+
+                               painter.setPen(whitePen);
+                               painter.drawText(bytePos, y - (18 + 6), buf);
+
+                               bytePos = x;
+
+                               if (bytePos > (xpos + width))
+                                       break;
+                       }
+               }
+       }
+
+       if (Global::synWaveLen[Global::trackNum] == 0)
+               return;
+
+       // Reset Y coord to the top
+       y = 7 + 12 + 18 + (40 * 1);
+       x = 0;
+       lastx = 0;
+
+       painter.setPen(orangePen);
+       painter.drawLine(lastx, y, x, y);
+       painter.drawLine(x, y, x + 4.0, y);
+       painter.drawLine(x + 4.0, y, x + 4.0, y - 17.0f);
+       painter.drawLine(x + 4.0, y - 17.0f, x + 8.0, y - 17.0f);
+       painter.drawLine(x + 8.0, y - 17.0f, x + 8.0, y);
+       lastx = x + 8.0;
+
+       for(uint32_t i=0; i<Global::synWaveLen[Global::trackNum]; i++)
+       {
+               uint32_t timeToNext = Global::synWave[Global::trackNum][i];
+               x += (double)timeToNext / 2.0;
+
+               if (x >= drawXPos)
+               {
+                       painter.setPen(orangePen);
+                       painter.drawLine(lastx, y, x, y);
+                       painter.drawLine(x, y, x + 4.0, y);
+                       painter.drawLine(x + 4.0, y, x + 4.0, y - 17.0f);
+                       painter.drawLine(x + 4.0, y - 17.0f, x + 8.0, y - 17.0f);
+                       painter.drawLine(x + 8.0, y - 17.0f, x + 8.0, y);
+                       lastx = x + 8.0;
+               }
+
+               char buf[10];
+
+               if ((i % 100) == 0)
+               {
+                       sprintf(buf, "|%d", i + 1);
+                       painter.setPen(whitePen);
+                       painter.drawText(x, y - (18 + 6), buf);
+               }
+
+               if (x > (xpos + width))
+                       break;
+       }
+
+       y = 7 + 12 + 18 + (40 * 2);
+       x = 0;
+       lastx = 0;
+
+       painter.setPen(orangePen);
+       painter.drawLine(lastx, y, x, y);
+       painter.drawLine(x, y, x + 4.0, y);
+       painter.drawLine(x + 4.0, y, x + 4.0, y - 17.0f);
+       painter.drawLine(x + 4.0, y - 17.0f, x + 8.0, y - 17.0f);
+       painter.drawLine(x + 8.0, y - 17.0f, x + 8.0, y);
+       lastx = x + 8.0;
+
+       for(uint32_t i=Global::waveSync; i<Global::synWaveLen[Global::trackNum]; i++)
+       {
+               uint32_t timeToNext = Global::synWave[Global::trackNum][i];
+               x += (double)timeToNext / 2.0;
+
+               if (x >= drawXPos)
+               {
+                       painter.setPen(orangePen);
+                       painter.drawLine(lastx, y, x, y);
+                       painter.drawLine(x, y, x + 4.0, y);
+                       painter.drawLine(x + 4.0, y, x + 4.0, y - 17.0f);
+                       painter.drawLine(x + 4.0, y - 17.0f, x + 8.0, y - 17.0f);
+                       painter.drawLine(x + 8.0, y - 17.0f, x + 8.0, y);
+                       lastx = x + 8.0;
+               }
+
+               char buf[10];
+
+               if ((i % 10) == 0)
+               {
+                       sprintf(buf, "|%d", i + 1);
+                       painter.setPen(whitePen);
+                       painter.drawText(x, y - (18 + 6), buf);
+               }
+
+               if (x > (xpos + width))
+                       break;
+       }
+}
+
+
+void WaveformWidget::mousePressEvent(QMouseEvent * event)
+{
+       if (event->button() == Qt::LeftButton)
+       {
+               event->accept();
+       }
+}
+
+
+void WaveformWidget::mouseMoveEvent(QMouseEvent * event)
+{
+       if (event->buttons() & Qt::LeftButton)
+       {
+               event->accept();
+       }
+}
+
+
+void WaveformWidget::mouseReleaseEvent(QMouseEvent * event)
+{
+       if (event->button() == Qt::LeftButton)
+       {
+               event->accept();
+       }
+}
+
+
+void WaveformWidget::mouseDoubleClickEvent(QMouseEvent * event)
+{
+       if (event->button() == Qt::LeftButton)
+       {
+               event->accept();
+       }
+}
+
+
+void WaveformWidget::keyPressEvent(QKeyEvent * event)
+{
+       int key = event->key();
+
+       if (key == Qt::Key_Up)
+       {
+       }
+       else if (key == Qt::Key_Down)
+       {
+       }
+       else if (key == Qt::Key_Left)
+       {
+       }
+       else if (key == Qt::Key_Right)
+       {
+       }
+       else
+               return;
+
+       // Only update if a key we recognize has been pressed!
+       update();
+}
+
+
+void WaveformWidget::keyReleaseEvent(QKeyEvent * /*event*/)
+{
+}
+
+
+void WaveformWidget::resizeEvent(QResizeEvent * /*event*/)
+{
+//     ResizeGrid();
+}
+
diff --git a/src/waveformwidget.h b/src/waveformwidget.h
new file mode 100644 (file)
index 0000000..19ccbf3
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef __WAVEFORMWIDGET_H__
+#define __WAVEFORMWIDGET_H__
+
+#include <QtWidgets>
+#include <stdint.h>
+
+class WaveformWidget: public QWidget
+{
+       Q_OBJECT
+
+       public:
+               WaveformWidget(QWidget * parent = 0);
+               ~WaveformWidget();
+
+       protected:
+               void paintEvent(QPaintEvent * event);
+               void mousePressEvent(QMouseEvent * event);
+               void mouseMoveEvent(QMouseEvent * event);
+               void mouseReleaseEvent(QMouseEvent * event);
+               void mouseDoubleClickEvent(QMouseEvent * event);
+               void keyPressEvent(QKeyEvent * event);
+               void keyReleaseEvent(QKeyEvent * event);
+               void resizeEvent(QResizeEvent * event);
+
+       signals:
+               void UpdateInfo(void);
+
+       public slots:
+               void HandleUpdate(void);
+               void HandleInitSync(void);
+               void HandleStepBack(void);
+               void HandleManualSync(void);
+               void HandleZeroAll(void);
+               void HandleSynthesize(void);
+               void HandleSynthesize2(void);
+               void HandleSync(int, int);
+               void HandleWaveSync(int);
+               void HandleRatio(int, int);
+};
+
+#endif // __WAVEFORMWIDGET_H__
+
diff --git a/wozmaker.pro b/wozmaker.pro
new file mode 100644 (file)
index 0000000..8c42cb9
--- /dev/null
@@ -0,0 +1,50 @@
+# Use 'qmake -o Makefile wozmaker.pro'
+
+CONFIG    += qt warn_on release debug
+RESOURCES += res/resources.qrc
+#LIBS      += -Ldxflib/lib -ldxf
+#LIBS      += -lao
+QT        += widgets
+
+# We stuff all the intermediate crap into obj/ so it won't confuse us mere mortals ;-)
+OBJECTS_DIR = obj
+MOC_DIR     = obj
+RCC_DIR     = obj
+UI_DIR      = obj
+
+INCLUDEPATH += \
+       src
+
+DEPENDPATH = \
+       src
+
+HEADERS = \
+       src/analysisthread.h \
+       src/app.h \
+       src/diskdrawthread.h \
+       src/diskwidget.h \
+       src/dsp.h \
+       src/fileio.h \
+       src/global.h \
+       src/infowidget.h \
+       src/mainwidget.h \
+       src/mainwin.h \
+       src/navwidget.h \
+       src/nibblewidget.h \
+       src/waveformwidget.h
+
+SOURCES = \
+       src/analysisthread.cpp \
+       src/app.cpp \
+       src/diskdrawthread.cpp \
+       src/diskwidget.cpp \
+       src/dsp.cpp \
+       src/fileio.cpp \
+       src/global.cpp \
+       src/infowidget.cpp \
+       src/mainwidget.cpp \
+       src/mainwin.cpp \
+       src/navwidget.cpp \
+       src/nibblewidget.cpp \
+       src/waveformwidget.cpp
+