Skip to content

Commit 666abbe

Browse files
committed
first commit
0 parents  commit 666abbe

23 files changed

+1162
-0
lines changed

CTape.cpp

+232
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
#include "ctape.h"
2+
3+
CTape::CTape()
4+
{
5+
TapeLength=0; //signal length on tape
6+
TapeData=NULL; //tape data
7+
Speed=1; //playback speed
8+
HeadPosition=0; //current position of the "head" of the recorder
9+
UseLeftChannel=true; //permission to use the left channel
10+
UseRightChannel=true; //permission to use the right channel
11+
Channels=0;
12+
}
13+
14+
CTape::~CTape()
15+
{
16+
Eject();
17+
}
18+
19+
bool CTape::LoadTape(char *FileName)
20+
{
21+
Eject();
22+
23+
HMMIO hwav;
24+
MMCKINFO parent,child;
25+
WAVEFORMATEX wfmtx;
26+
parent.ckid=(FOURCC)0;
27+
parent.cksize=0;
28+
parent.fccType=(FOURCC)0;
29+
parent.dwDataOffset=0;
30+
parent.dwFlags=0;
31+
child=parent;
32+
if ((hwav=mmioOpen(FileName,NULL,MMIO_READ|MMIO_ALLOCBUF))==NULL) return(false);
33+
parent.fccType=mmioFOURCC('W','A','V','E');
34+
if (mmioDescend(hwav,&parent,NULL,MMIO_FINDRIFF))
35+
{
36+
mmioClose(hwav,0);
37+
return(false);
38+
}
39+
child.ckid=mmioFOURCC('f','m','t',' ');
40+
if (mmioDescend(hwav,&child,&parent,0))
41+
{
42+
mmioClose(hwav,0);
43+
return(false);
44+
}
45+
if (mmioRead(hwav,(char *)&wfmtx,sizeof(wfmtx))!=sizeof(wfmtx))
46+
{
47+
mmioClose(hwav,0);
48+
return(false);
49+
}
50+
if (wfmtx.wFormatTag!=WAVE_FORMAT_PCM)
51+
{
52+
mmioClose(hwav,0);
53+
return(false);
54+
}
55+
if (mmioAscend(hwav,&child,0))
56+
{
57+
mmioClose(hwav,0);
58+
return(false);
59+
}
60+
child.ckid=mmioFOURCC('d','a','t','a');
61+
if (mmioDescend(hwav,&child,&parent,MMIO_FINDCHUNK))
62+
{
63+
mmioClose(hwav,0);
64+
return(false);
65+
}
66+
67+
//check the file format
68+
Channels=wfmtx.nChannels; //number of channels
69+
if (wfmtx.nSamplesPerSec!=44100) return(false); //check sample rate 44100
70+
if (wfmtx.nBlockAlign!=wfmtx.nChannels) return(false); //only 8 bit
71+
72+
//load sound data
73+
TapeData=new unsigned char[child.cksize];
74+
TapeLength=child.cksize;
75+
mmioRead(hwav,(char *)TapeData,child.cksize);
76+
TapeLength/=Channels; //make the length of one channel
77+
mmioClose(hwav,0);
78+
return(true);
79+
}
80+
81+
bool CTape::SetSpeed(long double speed)
82+
{
83+
if (Speed<=0) return(false);
84+
Speed=speed;
85+
return(true);
86+
}
87+
88+
bool CTape::ReadTape(unsigned char &volume)
89+
{
90+
if (TapeData==NULL) return(false);
91+
unsigned long pos=(unsigned long)HeadPosition;
92+
if (pos>=TapeLength) return(false);
93+
unsigned long left=pos;
94+
unsigned long right=pos+1;
95+
if (right>=TapeLength) right=pos;
96+
97+
//do a linear interpolation of the signal between neighboring points
98+
if (Channels==1) //for mono
99+
{
100+
long double k=((long double)(TapeData[right])-(long double)(TapeData[left]));
101+
double v=(double)(TapeData[left])+(HeadPosition-(long double)(pos))*k;
102+
volume=(unsigned char)v;
103+
}
104+
if (Channels==2) //for stereo
105+
{
106+
double ch_level=0;
107+
int ch_summ=0;
108+
if (UseLeftChannel==true)
109+
{
110+
long double k=((long double)(TapeData[right*2])-(long double)(TapeData[left*2]));
111+
ch_level+=(double)(TapeData[left*2])+(HeadPosition-(long double)(pos))*k;
112+
ch_summ++;
113+
}
114+
if (UseRightChannel==true)
115+
{
116+
long double k=((long double)(TapeData[right*2+1])-(long double)(TapeData[left*2+1]));
117+
ch_level+=(double)(TapeData[left*2+1])+(HeadPosition-(long double)(pos))*k;
118+
ch_summ++;
119+
}
120+
if (ch_summ==0) ch_summ=1;
121+
ch_level/=ch_summ;
122+
volume=(unsigned char)ch_level;
123+
}
124+
return(true);
125+
}
126+
127+
bool CTape::MoveHead(void)
128+
{
129+
HeadPosition+=Speed;
130+
unsigned long pos=(unsigned long)HeadPosition;
131+
if (pos>=TapeLength) return(false);
132+
return(true);
133+
}
134+
135+
bool CTape::ResetHead(void)
136+
{
137+
HeadPosition=0;
138+
return(true);
139+
}
140+
141+
unsigned long CTape::GetTapeLength(void)
142+
{
143+
return(TapeLength);
144+
}
145+
146+
void CTape::Eject(void)
147+
{
148+
if (TapeData!=NULL) delete(TapeData);
149+
HeadPosition=0;
150+
TapeData=NULL;
151+
TapeLength=0;
152+
}
153+
154+
bool CTape::ApplyFilter(void)
155+
{
156+
/*
157+
unsigned long n;
158+
int Filter=TapeData[0];
159+
for(n=0;n<TapeLength;n++)
160+
{
161+
Filter=Filter+TapeData[n];
162+
Filter/=2;
163+
TapeData[n]=Filter;
164+
}
165+
*/
166+
return(true);
167+
}
168+
169+
long double CTape::GetSpeed(void)
170+
{
171+
return(Speed);
172+
}
173+
174+
bool CTape::EndOfTape(void)
175+
{
176+
unsigned char volume;
177+
if (ReadTape(volume)==false) return(true); //tape finished
178+
return(false); //tape not finished
179+
}
180+
181+
unsigned char CTape::GetLevel(int Step)
182+
{
183+
unsigned long h_p=(unsigned long)HeadPosition;
184+
int n;
185+
unsigned long level=0;
186+
int max=0;
187+
int min=255;
188+
if (h_p+Step>=TapeLength) h_p=TapeLength-Step;
189+
if (TapeLength<Step)
190+
{
191+
h_p=0;
192+
Step=TapeLength;
193+
}
194+
for(n=0;n<Step;n++,h_p++)
195+
{
196+
unsigned char volume;
197+
if (Channels==1) volume=TapeData[h_p]; //for mono
198+
if (Channels==2)
199+
{
200+
int ch_level=0;
201+
int ch_summ=0;
202+
if (UseLeftChannel==true)
203+
{
204+
ch_level+=TapeData[h_p*2];
205+
ch_summ++;
206+
}
207+
if (UseRightChannel==true)
208+
{
209+
ch_level+=TapeData[h_p*2+1];
210+
ch_summ++;
211+
}
212+
if (ch_summ==0) ch_summ=1;
213+
ch_level/=ch_summ;
214+
volume=ch_level;
215+
}
216+
level+=volume;
217+
if (volume>max) max=volume;
218+
if (volume<min) min=volume;
219+
}
220+
if (n!=0) level/=n;
221+
int center=(max+min)/2;
222+
level=(level+center)/2;
223+
return((unsigned char)level);
224+
}
225+
226+
bool CTape::SetUseChannel(bool use_left_channel,bool use_right_channel)
227+
{
228+
UseLeftChannel=use_left_channel;
229+
UseRightChannel=use_right_channel;
230+
return(true);
231+
}
232+

CTape.h

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#ifndef CTAPE_H
2+
#define CTAPE_H
3+
4+
#include "stdafx.h"
5+
6+
class CTape
7+
{
8+
protected:
9+
10+
unsigned long TapeLength;
11+
unsigned char *TapeData;
12+
long double Speed;
13+
long double HeadPosition;
14+
int Channels;
15+
bool UseLeftChannel;
16+
bool UseRightChannel;
17+
18+
public:
19+
20+
CTape();
21+
~CTape();
22+
23+
bool LoadTape(char *FileName);
24+
bool SetSpeed(long double speed);
25+
bool ReadTape(unsigned char &volume);
26+
bool MoveHead(void);
27+
bool ResetHead(void);
28+
unsigned long GetTapeLength(void);
29+
void Eject(void);
30+
bool ApplyFilter(void);
31+
long double GetSpeed(void);
32+
bool EndOfTape(void);
33+
unsigned char GetLevel(int Step);
34+
bool SetUseChannel(bool use_left_channel,bool use_right_channel);
35+
};
36+
37+
#endif

Main.cpp

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#include "stdafx.h"
2+
#include "cdialog_main.h"
3+
4+
class CWinApp_Main:public CWinApp
5+
{
6+
protected:
7+
8+
public:
9+
10+
CWinApp_Main(void);
11+
12+
~CWinApp_Main();
13+
14+
BOOL InitInstance(void);
15+
16+
};
17+
18+
CWinApp_Main::CWinApp_Main(void)
19+
{
20+
}
21+
22+
CWinApp_Main::~CWinApp_Main()
23+
{
24+
}
25+
26+
BOOL CWinApp_Main::InitInstance(void)
27+
{
28+
CDialog_Main cDialog_Main((LPSTR)IDD_DIALOG_MAIN,NULL);
29+
cDialog_Main.DoModal();
30+
return(TRUE);
31+
}
32+
33+
CWinApp_Main cWinAppMain;
34+
35+

README.md

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
The signal on the ZX-Spectrum tape is a frequency-modulated signal.
2+
Zero is encoded with the highest frequency. The clock/sync signal is slightly higher frequency.
3+
One is encoded with double the frequency of zero.
4+
Start tone has the frequency 2.5 times lower than the zero frequency.
5+
Encoded start tone sounds pi-i-i-i-i at the beginning of the tape.
6+
7+
All signals are rectangular:
8+
9+
_ __
10+
| | | - clock/sync signal.
11+
|__| |_
12+
_ ___
13+
| | | - zero or sync.
14+
|___| |_
15+
16+
_ ______
17+
| | | - one.
18+
|______| |_
19+
20+
_ ________
21+
| | | - start tone.
22+
|________| |_
23+
24+
25+
In general, the ZX-Spectrum signal looks like this:
26+
27+
_ ________ ________ __ ___ ______
28+
| | | | | | | | | | |
29+
|________| |________| |__| |___| |______| |
30+
31+
start tone sync signal zero one
32+
33+
34+
The program analyzes only the upper parts of the signals, respectively, the program specifies the duration of these parts of the signals in the samples of the sound file multiplied by 5. That is, if a high level of the signal in the sound file takes 30 counts, then in the duration we write 150.
35+
Only files with parameters 44100Hz, 8 bits, mono or stereo, not compressed, are decrypted.
36+
Such files can be easily obtained from recording programs.
37+
38+
The signal level needs to be known in order to decide whether to receive a signal for a part of the high level or for a part of a low level. For this, two methods are used:
39+
- Automatic. The computer analyzes the signal for N samples of audio data forward, averages signals and learns the average level (because the signals have the upper and them, then the middle will be average).
40+
- Manual. The user himself sets the value of the level. For ideal files, this value is 127 - the middle of the range 0-255.
41+
42+
When recording from a tape recorder, it is recommended that the signal be all within the range 0-255, and there was no clipping for too strong a signal level. That is, the volume is needed to be
43+
small. Moreover, the noise at high volume also increases.
44+
45+
Successful decoding! :)
46+
47+
(c) Äìèòðèé Òðóíîâ (Dmitry Trunov) (da-nie), August 21, 2009, http://www.animekazan.net/forum2

Release/CTape.obj

5.8 KB
Binary file not shown.

Release/DELETE.BAT

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
del *.obj
2+
del *.pch
3+
del *.idb
4+
del *.res
5+
6+

Release/Main.obj

7.42 KB
Binary file not shown.

Release/Resource.res

2.14 KB
Binary file not shown.

Release/Wav2Tap_Converter.exe

24 KB
Binary file not shown.

Release/Wav2Tap_Converter.pch

5.81 MB
Binary file not shown.

Release/cdialog_main.obj

21.4 KB
Binary file not shown.

Release/vc60.idb

49 KB
Binary file not shown.

Resource.aps

34.4 KB
Binary file not shown.

0 commit comments

Comments
 (0)