Skip to content

Commit 3e233aa

Browse files
committed
first working version of cas to wav converter
1 parent 97427b9 commit 3e233aa

File tree

1 file changed

+84
-71
lines changed

1 file changed

+84
-71
lines changed

Diff for: src/msxtape.py

+84-71
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
Encoding as per: https://github.com/oboroc/msx-books/blob/master/ru/msx2-fb-1993-ru.md#10
55
"""
66

7-
import sys, wave
7+
import sys, os, wave
88

99
class wav_writer:
1010
def __init__(self, s_rate = 44100.0, s_width = 1):
@@ -38,7 +38,6 @@ def write(self, f_name):
3838
f.setsampwidth(self.sample_width)
3939
f.setframerate(self.sample_rate)
4040
f.writeframes(bytearray(self.pcm_data))
41-
del ba
4241

4342

4443
def add_value(self, value):
@@ -130,12 +129,6 @@ def add_long_header(self, freq):
130129
self.add_short_header(freq)
131130

132131

133-
def add_cas(self, freq, cas):
134-
"""
135-
take object cas and add pcm data based on it
136-
"""
137-
138-
139132
CAS_HEADER = [0x1f, 0xa6, 0xde, 0xba, 0xcc, 0x13, 0x7d, 0x74]
140133
CAS_HEADER_LEN = len(CAS_HEADER)
141134
BASIC = 0xd3
@@ -191,33 +184,22 @@ def dechex(n):
191184
self.blocks = []
192185
while idx < len(cas_data):
193186
if not is_cas_header(cas_data, idx):
194-
print('Error: no valid cas header at', dechex(idx))
195-
return
187+
raise ValueError('no valid cas header at ' + dechex(idx))
196188
idx = idx + CAS_HEADER_LEN
197189
# is it a 10 byte block header?
198190
if reps(cas_data, idx, BLOCK_HEADER_LEN) >= BLOCK_HEADER_LEN:
199191
block_type = cas_data[idx]
200192
idx = idx + BLOCK_HEADER_LEN
201193
else:
202194
block_type = CUSTOM
203-
if block_type == BASIC:
204-
s = 'BASIC'
205-
elif block_type == ASCII:
206-
s = 'ASCII'
207-
elif block_type == BINARY:
208-
s = 'BINARY'
209-
else:
210-
s = 'CUSTOM'
211-
#print(s, 'block start at', dechex(idx))
212195
# 6 bytes file name and cas header
213196
block_fname = ''
214197
if block_type in [BASIC, ASCII, BINARY]:
215198
for i in range(FNAME_LEN):
216199
block_fname = block_fname + chr(cas_data[idx + i])
217200
idx = idx + FNAME_LEN
218201
if not is_cas_header(cas_data, idx):
219-
print('Error: no cas header after cas file name at', dechex(idx))
220-
return
202+
raise ValueError('no cas header after cas file name at ' + dechex(idx))
221203
idx = idx + CAS_HEADER_LEN
222204
block_data = []
223205
start_address = end_address = run_address = -1
@@ -230,15 +212,14 @@ def dechex(n):
230212
break
231213
block_data.append(cas_data[idx])
232214
idx = idx + 1
233-
#print('BASIC block end at', dechex(idx))
234215
elif block_type == ASCII:
235216
ASCII_SEQ_LEN = 256
236217
EOF = 0x1a
237218
while idx < len(cas_data):
238219
if len(cas_data) - idx < ASCII_SEQ_LEN:
239-
print('Error: expected', ASCII_SEQ_LEN, 'bytes sequence in ASCII block', block_fname,
240-
'; there is only', len(cas_data) - idx, 'bytes of data left')
241-
return
220+
raise ValueError('expected ' + str(ASCII_SEQ_LEN) + ' bytes sequence in ASCII block ' +
221+
block_fname + '; there is only' + str(len(cas_data) - idx) +
222+
' bytes of data left')
242223
found_eof = False
243224
for i in range(ASCII_SEQ_LEN):
244225
block_data.append(cas_data[idx + i])
@@ -248,54 +229,42 @@ def dechex(n):
248229
if found_eof:
249230
break
250231
if not is_cas_header(cas_data, idx):
251-
#print('Error: no cas header for next ASCII sequence at', dechex(idx))
252-
return
232+
raise ValueError('no cas header for next ASCII sequence at ' + dechex(idx))
253233
idx = idx + CAS_HEADER_LEN
254-
#print('ASCII block end at', dechex(idx))
255234
if not found_eof:
256-
print('Error: no eof found in ascii block at', dechex(idx))
257-
return
235+
raise ValueError('no eof found in ascii block at ' + dechex(idx))
258236
elif block_type == BINARY:
259237
start_address = cas_data[idx] + cas_data[idx + 1] * 256
260-
#print('start address:', dechex(start_address))
261238
end_address = cas_data[idx + 2] + cas_data[idx + 3] * 256
262-
#print('end address: ', dechex(end_address))
263239
run_address = cas_data[idx + 4] + cas_data[idx + 5] * 256
264-
#print('run address: ', dechex(run_address))
265240
code_len = end_address - start_address + 1
266-
#print('code length: ', dechex(code_len))
267241
idx = idx + 6
268242
bin_start = idx
269243
if idx + code_len > len(cas_data):
270-
print('Error: unexpected end in binary block data')
271-
return
244+
raise ValueError('unexpected end in binary block data at ' + dechex(idx))
272245
while idx < len(cas_data):
273246
if is_cas_header(cas_data, idx):
274247
break
275248
block_data.append(cas_data[idx])
276249
idx = idx + 1
277-
#print('block length:', dechex(idx - bin_start))
278-
#print('BINARY block end at', dechex(idx))
279250
elif block_type == CUSTOM:
280251
while idx < len(cas_data):
281252
if is_cas_header(cas_data, idx):
282253
break
283254
block_data.append(cas_data[idx])
284255
idx = idx + 1
285-
#print('CUSTOM block end at', dechex(idx))
286256
else:
287-
print('Error: this is a bug, this code should never be reached')
288-
return
257+
raise ValueError('this is a bug, this code should never be reached')
289258
self.blocks.append([block_type, block_fname, block_data, start_address, end_address, run_address])
259+
del cas_data
290260

291261

292-
def write(self, cas_name):
262+
def write(self, fname, is_wav = False, s_rate = 44100.0, s_width = 1):
293263
"""
294-
create a cas file from cas_data
264+
create a cas or wav (if is_wav == True) file from cas_data
295265
"""
296266
if self.blocks == []:
297-
print('Error: no cas data, nothing to write to', cas_name)
298-
return
267+
raise ValueError('no cas data, nothing to write to ' + fname)
299268
cas_data = []
300269
for block in self.blocks:
301270
block_type = block[0]
@@ -304,36 +273,82 @@ def write(self, cas_name):
304273
start_address = block[3]
305274
end_address = block[4]
306275
run_address = block[5]
307-
cas_data.extend(CAS_HEADER)
276+
if is_wav:
277+
ww = wav_writer(s_rate, s_width)
278+
freq = 1200.0
279+
ww.add_long_header(freq)
280+
else:
281+
cas_data.extend(CAS_HEADER)
308282
if block_type in [BASIC, ASCII, BINARY]:
309283
for i in range(BLOCK_HEADER_LEN):
310-
cas_data.append(block_type)
284+
if is_wav:
285+
ww.add_byte(freq, block_type)
286+
else:
287+
cas_data.append(block_type)
311288
for i in range(FNAME_LEN):
312-
cas_data.append(ord(block_fname[i]))
289+
if is_wav:
290+
ww.add_byte(freq, ord(block_fname[i]))
291+
else:
292+
cas_data.append(ord(block_fname[i]))
313293
if block_type == BASIC:
314-
cas_data.extend(CAS_HEADER)
315-
cas_data.extend(block_data)
294+
if is_wav:
295+
ww.add_short_header(freq)
296+
for i in range(len(block_data)):
297+
ww.add_byte(freq, block_data[i])
298+
else:
299+
cas_data.extend(CAS_HEADER)
300+
cas_data.extend(block_data)
316301
elif block_type == ASCII:
317302
for i in range(len(block_data)):
318303
if i % 256 == 0:
319-
cas_data.extend(CAS_HEADER)
320-
cas_data.append(block_data[i])
304+
if is_wav:
305+
ww.add_short_header(freq)
306+
else:
307+
cas_data.extend(CAS_HEADER)
308+
if is_wav:
309+
ww.add_byte(freq, block_data[i])
310+
else:
311+
cas_data.append(block_data[i])
321312
elif block_type == BINARY:
322-
cas_data.extend(CAS_HEADER)
323-
cas_data.append(start_address & 0xff)
324-
cas_data.append((start_address & 0xff00) >> 8)
325-
cas_data.append(end_address & 0xff)
326-
cas_data.append((end_address & 0xff00) >> 8)
327-
cas_data.append(run_address & 0xff)
328-
cas_data.append((run_address & 0xff00) >> 8)
329-
cas_data.extend(block_data)
313+
start_lo = start_address & 0xff
314+
start_hi = (start_address & 0xff00) >> 8
315+
end_lo = end_address & 0xff
316+
end_hi = (end_address & 0xff00) >> 8
317+
run_lo = run_address & 0xff
318+
run_hi = (run_address & 0xff00) >> 8
319+
if is_wav:
320+
ww.add_short_header(freq)
321+
ww.add_byte(freq, start_lo)
322+
ww.add_byte(freq, start_hi)
323+
ww.add_byte(freq, end_lo)
324+
ww.add_byte(freq, end_hi)
325+
ww.add_byte(freq, run_lo)
326+
ww.add_byte(freq, run_hi)
327+
for i in range(len(block_data)):
328+
ww.add_byte(freq, block_data[i])
329+
else:
330+
cas_data.extend(CAS_HEADER)
331+
cas_data.append(start_lo)
332+
cas_data.append(start_hi)
333+
cas_data.append(end_lo)
334+
cas_data.append(end_hi)
335+
cas_data.append(run_lo)
336+
cas_data.append(run_hi)
337+
cas_data.extend(block_data)
330338
elif block_type == CUSTOM:
331-
cas_data.extend(block_data)
339+
if is_wav:
340+
for i in range(len(block_data)):
341+
ww.add_byte(freq, block_data[i])
342+
else:
343+
cas_data.extend(block_data)
332344
else:
333-
print('Error: invalid block type', block_type)
334-
return
335-
with open(cas_name, 'wb') as f:
336-
f.write(bytearray(cas_data))
345+
raise ValueError('invalid block type ' + hex(block_type))
346+
if is_wav:
347+
ww.write(fname)
348+
else:
349+
with open(fname, 'wb') as f:
350+
f.write(bytearray(cas_data))
351+
del cas_data
337352

338353

339354
def main():
@@ -343,12 +358,10 @@ def main():
343358
for i in range(1, len(sys.argv)):
344359
c = cas()
345360
c.read(sys.argv[i])
346-
c.write('---' + sys.argv[i])
347-
print('---')
348-
# t = wav_writer()
349-
# t.add_cas(1200, c)
350-
# t.write('test.wav')
351-
# del t
361+
# c.write('~' + sys.argv[i])
362+
bn = os.path.basename(sys.argv[i])
363+
fname = os.path.splitext(bn)[0] + '.wav'
364+
c.write(fname, True)
352365
del c
353366

354367

0 commit comments

Comments
 (0)