ciderpress/app/CassetteDialog.h
Andy McFadden d8223dbcfd Relocate method comments
This moves method comments from the .cpp file to the .h file,
where users of the methods can find them.  This also makes it
possible for the IDE to show the comments when you mouse-hover over
the method name, though Visual Studio is a bit weak in this regard.

Also, added "override" keywords on overridden methods.  Reasonably
current versions of popular compilers seem to support this.

Also, don't have the return type on a separate line in the .cpp file.
The motivation for the practice -- quickly finding a method definition
with "^name" -- is less useful in C++ than C, and modern IDEs provide
more convenient ways to do the same thing.

Also, do some more conversion from unsigned types to uintXX_t.

This commit is primarily for the "app" directory.
2014-11-21 22:33:39 -08:00

230 lines
7.3 KiB
C++

/*
* CiderPress
* Copyright (C) 2007 by faddenSoft, LLC. All Rights Reserved.
* See the file LICENSE for distribution terms.
*/
/*
* Apple II cassette I/O functions.
*/
#ifndef APP_CASSETTEDIALOG_H
#define APP_CASSETTEDIALOG_H
/*
* The dialog box is primarily concerned with extracting the original data
* from a WAV file recording of an Apple II cassette tape.
*/
class CassetteDialog : public CDialog {
public:
CassetteDialog(CWnd* pParentWnd = NULL) :
CDialog(IDD_IMPORTCASSETTE, pParentWnd), fDirty(false)
{}
virtual ~CassetteDialog(void) {}
CString fFileName; // file to open
bool IsDirty(void) const { return fDirty; }
private:
virtual BOOL OnInitDialog(void) override;
//virtual void DoDataExchange(CDataExchange* pDX);
//virtual void OnOK(void);
//enum { WMU_DIALOG_READY = WM_USER+2 };
/*
* Something changed in the list. Update the "OK" button.
*/
afx_msg void OnListChange(NMHDR* pNotifyStruct, LRESULT* pResult);
/*
* The volume filter drop-down box has changed.
*/
afx_msg void OnAlgorithmChange(void);
/*
* User pressed "import" button. Add the selected item to the current
* archive or disk image.
*/
afx_msg void OnImport(void);
afx_msg void OnListDblClick(NMHDR* pNotifyStruct, LRESULT* pResult);
afx_msg void OnHelp(void);
/*
* This holds converted data from the WAV file, plus some meta-data
* like what type of file we think this is.
*/
class CassetteData {
public:
CassetteData(void) : fFileType(0x00), fOutputBuf(NULL), fOutputLen(-1),
fStartSample(-1), fEndSample(-1), fChecksum(0x00),
fChecksumGood(false)
{}
virtual ~CassetteData(void) { delete[] fOutputBuf; }
/*
* Algorithm to use. This must match up with the order of the items
* in the dialog IDC_CASSETTE_ALG combo box.
*/
typedef enum Algorithm {
kAlgorithmMIN = -1,
kAlgorithmZero = 0,
kAlgorithmSharpPeak,
kAlgorithmRoundPeak,
kAlgorithmShallowPeak,
kAlgorithmMAX
} Algorithm;
/*
* Scan the WAV file, starting from the specified byte offset.
*
* Returns "true" if we found a file, "false" if not (indicating that the
* end of the input has been reached). Updates "*pStartOffset" to point
* past the end of the data we've read.
*/
bool Scan(SoundFile* pSoundFile, Algorithm alg, long* pSampleOffset);
unsigned char* GetDataBuf(void) const { return fOutputBuf; }
int GetDataLen(void) const { return fOutputLen; }
int GetDataOffset(void) const { return fStartSample; }
int GetDataEndOffset(void) const { return fEndSample; }
unsigned char GetDataChecksum(void) const { return fChecksum; }
bool GetDataChkGood(void) const { return fChecksumGood; }
long GetFileType(void) const { return fFileType; }
void SetFileType(long fileType) { fFileType = fileType; }
private:
typedef enum Phase {
kPhaseUnknown = 0,
kPhaseScanFor770Start,
kPhaseScanning770,
kPhaseScanForShort0,
kPhaseShort0B,
kPhaseReadData,
kPhaseEndReached,
// kPhaseError,
} Phase;
typedef enum Mode {
kModeUnknown = 0,
kModeInitial0,
kModeInitial1,
kModeInTransition,
kModeAtPeak,
kModeRunning,
} Mode;
typedef struct ScanState {
Algorithm algorithm;
Phase phase;
Mode mode;
bool positive; // rising or at +peak if true
long lastZeroIndex; // in samples
long lastPeakStartIndex; // in samples
float lastPeakStartValue;
float prevSample;
float halfCycleWidth; // in usec
long num770; // #of consecutive 770Hz cycles
long dataStart;
long dataEnd;
/* constants */
float usecPerSample;
} ScanState;
/*
* Convert a block of samples from PCM to float.
*
* Only the first (left) channel is converted in multi-channel formats.
*/
void ConvertSamplesToReal(const WAVEFORMATEX* pFormat,
const unsigned char* buf, long chunkLen, float* sampleBuf);
/*
* Process one audio sample. Updates "pScanState" appropriately.
*
* If we think we found a bit, this returns "true" with 0 or 1 in "*pBitVal".
*/
bool ProcessSample(float sample, long sampleIndex,
ScanState* pScanState, int* pBitVal);
/*
* Process the data by measuring the distance between zero crossings.
*
* This is very similar to the way the Apple II does it, though
* we have to scan for the 770Hz lead-in instead of simply assuming the
* the user has queued up the tape.
*
* To offset the effects of DC bias, we examine full cycles instead of
* half cycles.
*/
bool ProcessSampleZero(float sample, long sampleIndex,
ScanState* pScanState, int* pBitVal);
/*
* Process the data by finding and measuring the distance between peaks.
*/
bool ProcessSamplePeak(float sample, long sampleIndex,
ScanState* pScanState, int* pBitVal);
/*
* Given the width of a half-cycle, update "phase" and decide whether or not
* it's time to emit a bit.
*
* Updates "halfCycleWidth" too, alternating between 0.0 and a value.
*
* The "sampleIndex" parameter is largely just for display. We use it to
* set the "start" and "end" pointers, but those are also ultimately just
* for display to the user.
*/
bool UpdatePhase(ScanState* pScanState, long sampleIndex,
float halfCycleUsec, int* pBitVal);
enum {
kMaxFileLen = 65535+2+1+1, // 64K + length + checksum + 1 slop
};
long fFileType; // 0x06, 0xfa, or 0xfc
unsigned char* fOutputBuf;
int fOutputLen;
long fStartSample;
long fEndSample;
unsigned char fChecksum;
bool fChecksumGood;
};
/*
* Analyze the contents of a WAV file.
*
* Returns true if it found anything at all, false if not.
*/
bool AnalyzeWAV(void);
/*
* Add an entry to the list.
*
* Layout: index format length checksum start-offset
*/
void AddEntry(int idx, CListCtrl* pListCtrl, long* pFileType);
enum {
kMaxRecordings = 100, // max A2 files per WAV file
};
/* array with one entry per file */
CassetteData fDataArray[kMaxRecordings];
CassetteData::Algorithm fAlgorithm;
bool fDirty;
DECLARE_MESSAGE_MAP()
};
#endif /*APP_CASSETTEDIALOG_H*/