Seite 2 von 7
Re: Dragon 32 Homecomputer Kassetten in ASCII umwandeln...
Verfasst: Freitag 16. August 2013, 14:54
von EyDu
@jerch: warum die ganze händische Bytearbeite? Wenn du auf Geschwindigkeit optimieren willst, dann bietet sich wohl eher eine Lookup-Tabelle an.
Code: Alles auswählen
def reverse_bits(b, length=8):
r = 0
for _ in range(length):
r = (r << 1) | (b & 1)
b >>= 1
return r
Re: Dragon 32 Homecomputer Kassetten in ASCII umwandeln...
Verfasst: Freitag 16. August 2013, 14:58
von jens
Also die Code Stücke werfen bei mir keine brauchbaren Daten aus. (Dumm, das Forum hat ja immer noch den & Bug)
Re: Dragon 32 Homecomputer Kassetten in ASCII umwandeln...
Verfasst: Freitag 16. August 2013, 15:09
von jerch
@jens:
Kannst Du die Rohdaten irgendwie zugänglich machen? Dann wirds vllt einfacher.
Ich frage mich hier sowieso, warum Du dass alles auf Bitebene machst. Kannst Du nicht einfach den initialen Offset des Headers bestimmen und dann auf alignment-korrigierten Bytes arbeiten?
@EyDu:
Ja iss'n fauler Kompromiss mit etwas Geschwindigkeitsvorteil, den ich in c gerne nutze. Ein lookup table ist natürlich schneller.
Re: Dragon 32 Homecomputer Kassetten in ASCII umwandeln...
Verfasst: Freitag 16. August 2013, 15:17
von jens
Re: Dragon 32 Homecomputer Kassetten in ASCII umwandeln...
Verfasst: Freitag 16. August 2013, 15:29
von jens
Hab gerade nochmal einen pull des aktuellen Stands gemacht:
https://github.com/jedie/python-code-sn ... 9b258cea6d
Hab ein BASIC token dict eingefügt, sieht so aus:
Code: Alles auswählen
BASIC_TOKENS = {
128: " FOR ", # 0x80
129: " GO ", # 0x81
130: " REM ", # 0x82
131: "'", # 0x83
132: " ELSE ", # 0x84
133: " IF ", # 0x85
...
Der wird genutzt zum umwandeln. Aber in der einfachen Art und weise:
Code: Alles auswählen
def block2ascii(bit_list):
for block in iter_steps(bit_list, steps=8):
byte_no = bits2ASCII(block)
if byte_no in BASIC_TOKENS:
character = BASIC_TOKENS[byte_no]
else:
character = chr(byte_no)
print "%s %4s %3s %s" % (
list2str(block), hex(byte_no), byte_no, repr(character)
)
Raus kommt dann u.a. das:
Code: Alles auswählen
...
11100001 0x87 135 ' PRINT '
00000100 0x20 32 ' '
10010010 0x49 73 'I'
11011100 0x3b 59 ';'
01000100 0x22 34 '"'
00010010 0x48 72 'H'
10100010 0x45 69 'E'
00110010 0x4c 76 'L'
00110010 0x4c 76 'L'
11110010 0x4f 79 'O'
00000100 0x20 32 ' '
11101010 0x57 87 'W'
11110010 0x4f 79 'O'
01001010 0x52 82 'R'
00110010 0x4c 76 'L'
00100010 0x44 68 'D'
10000100 0x21 33 '!'
01000100 0x22 34 '"'
00000000 0x0 0 '\x00'
...
Das sieht man allerdings aktuell nur mit
FILENAME = "HelloWorld1 xroar.wav" nicht mit der anderen WAVE...
Deswegen hab ich mal ein Test gemacht:
Code: Alles auswählen
TEST_STR=(
"00010010" # 0x48 72 'H'
"10100010" # 0x45 69 'E'
"00110010" # 0x4c 76 'L'
"00110010" # 0x4c 76 'L'
"11110010" # 0x4f 79 'O'
"00000100" # 0x20 32 ' '
"11101010" # 0x57 87 'W'
"11110010" # 0x4f 79 'O'
"01001010" # 0x52 82 'R'
"00110010" # 0x4c 76 'L'
"00100010" # 0x44 68 'D'
"10000100" # 0x21 33 '!'
)# 000100101010001000110010001100101111001000000100111010101111001001001010001100100010001010000100
test_start = get_start_pos_iter_window(bit_list, TEST_STR)
print "*** Test String found at:", test_start
In beiden WAV Dateien wird dieser Teil gefunden!
Also ist es wieder nicht synchron...
Aktuell wird auch nur nachgesehen wo sich
START_LEADER = "10101010" befindet und dann alles in 8Bits zerhackt. Denke das ist nicht das richtige...
Re: Dragon 32 Homecomputer Kassetten in ASCII umwandeln...
Verfasst: Freitag 16. August 2013, 16:23
von jens
[quote="jerch"]Hier mal in c-hackisch:
Code: Alles auswählen
...
sentinel = c_ubyte()
i_bits = iter(bits)
for bit in i_bits:
sentinel.value <<= 1
sentinel.value |= bit
if sentinel.value == 42: # ?? nicht spec-konform
break
...[/quote]
Hab mir den code nochmal genauer angesehen.
Kann es sein, das im Grunde hier in dem Teil im Prinzip das selbe gemacht wird, wie bei mir? Also das man bit für bit durchgeht und ein bestimmtes Muster zu suchen? In diesem Fall halt [b]START_LEADER = "10101010"[/b]
Wobei ich mir nun überlegt habe, das gerade [b]10101010[/b] ziemlich doof ist. Denn die genau Position kann in diesem Fall doch sehr leicht um 2 Bits vor/zurück verschoben sein und doch passt es.
Bei http://www.onastick.clara.net/cosio.htm steht auch was von einem sync byte:
[b]1. A leader byte - $55
2. A sync byte - $3C[/b]
Kann es sein, das man besser das suchen sollte?
EDIT: Kann es sein, das 0x3C das ist: [b]00111100[/b] ?
Das würde auch mehr Sinn machen!
Re: Dragon 32 Homecomputer Kassetten in ASCII umwandeln...
Verfasst: Freitag 16. August 2013, 16:28
von jens
Ha! Ich denke genau das ist es!
Mit
HelloWorld1 xroar.wav (was funktioniert):
*** file info block data:
00111100 00000000 11110000...
Mit
HelloWorld1 origin.wav (was nicht funktioniert):
*** file info block data:
10101000 11110000 0000001...
Hab das "sync byte" mal unterstrichen. Wie es aussieht ist das "verschoben"...
Re: Dragon 32 Homecomputer Kassetten in ASCII umwandeln...
Verfasst: Freitag 16. August 2013, 16:50
von jens
glaube das hilft:
Code: Alles auswählen
def goto_next_block(bit_list, debug=False):
"""
>>> bits = (
... "10101010" # 0x55 leader byte
... "00111100" # 0x3C sync byte
... "00010010" # 0x48 'H'
... )
>>> bit_list = [int(i) for i in bits]
>>> bit_list = goto_next_block(bit_list)
>>> bit_list
[0, 0, 0, 1, 0, 0, 1, 0]
more bits inserted:
>>> bits = ("1010" # inserted
... "101010100011110000010010")
>>> goto_next_block([int(i) for i in bits])
[0, 0, 0, 1, 0, 0, 1, 0]
no complete leader byte
>>> bits = ("1010" # incomplete
... "0011110000010010")
>>> goto_next_block([int(i) for i in bits])
[0, 0, 0, 1, 0, 0, 1, 0]
"""
end = get_last_pos_iter_steps(bit_list, LEADER_BYTE)
if not end:
if debug:
print "INFO: leader byte block end not found."
else:
if debug:
print "leader byte block end found at:", end
bit_list = bit_list[end:]
sync_pos = get_start_pos_iter_window(bit_list, SYNC_BYTE)
if sync_pos is None:
if debug:
print "ERROR: Sync byte '%s' not found!" % SYNC_BYTE
sys.exit(-1)
if debug:
print "Sync byte '%s' found at position: %i" % (SYNC_BYTE, sync_pos)
# Cut until sync byte
cut_pos = sync_pos + len(SYNC_BYTE)
bit_list = bit_list[cut_pos:]
return bit_list
Re: Dragon 32 Homecomputer Kassetten in ASCII umwandeln...
Verfasst: Freitag 16. August 2013, 19:33
von snafu
jens hat geschrieben:EDIT: Kann es sein, das 0x3C das ist: 00111100 ?
Das würde auch mehr Sinn machen!
Na, das ist ja wohl schnell rauszufinden. Wenn man keine Lust hat, selber zu rechnen:
Also offensichtlich ist es so.
Re: Dragon 32 Homecomputer Kassetten in ASCII umwandeln...
Verfasst: Freitag 16. August 2013, 20:04
von jens
Wie kann man eigentlich das auf "einfache" Weise auffüllen? Also das man wieder
00111100 erhält?
Re: Dragon 32 Homecomputer Kassetten in ASCII umwandeln...
Verfasst: Freitag 16. August 2013, 20:28
von darktrym
Re: Dragon 32 Homecomputer Kassetten in ASCII umwandeln...
Verfasst: Freitag 16. August 2013, 20:32
von BlackJack
@darktrym: Die Frage war nach *einfach*. Oder gingst Du davon aus das die Anführungsstriche nach einer möglichst komplizierten Variante verlangten?
Re: Dragon 32 Homecomputer Kassetten in ASCII umwandeln...
Verfasst: Freitag 16. August 2013, 20:37
von darktrym
Zuspät, ein Glas Bier hat den Weg zur Lösung verlängert.
Re: Dragon 32 Homecomputer Kassetten in ASCII umwandeln...
Verfasst: Freitag 16. August 2013, 23:35
von jerch
@jens:
Ich hab mir mal Deine origin-Aufnahme angeschaut, Du hast da ein tieffrequentes Störsignal drin (Netzbrummen?). Es ist nicht sehr laut, könnte aber dazu führen, dass Du für die Nulldurchgänge die falsche Frequenz und damit falsche Bitsequenz berechnest. Damit Dein Wave-Decoder mit sowas zuverlässig umgehen kann, solltest Du einen Hochpassfilter einbauen.
Re: Dragon 32 Homecomputer Kassetten in ASCII umwandeln...
Verfasst: Freitag 16. August 2013, 23:52
von jens
Die Aufnahme die du meinst, hatte ich frisch digitalisiert. Also Dragon Rechner direkt in Soundkarte gepackt.
Aufnahmen die auf Kassette aufgenommen und dann davon wiedergegeben, dürften noch viel mehr Störgeräusche haben
Der aktuelle Code funktioniert aber mit beiden WAV Dateien die auf github sind.
Re: Dragon 32 Homecomputer Kassetten in ASCII umwandeln...
Verfasst: Samstag 17. August 2013, 22:43
von jens
Also ich bin schon eine ganze Ecke weiter gekommen. Den BASIC code von meinem Beispiel erhalte ich mittlerweile.
Doch so generell gehe ich wohl aus Unwissenheit nicht den best practice weg.
Ich erhalte ja über die WAVE Datei eine Liste von einsen und nullen... Darin muß ich ein "Sync Byte" finden und könnte dann wahrscheinlich alles zu einer Liste von bytes wandeln oder direkt einem binären String.
Doch bisher belasse ich es bei der "Bit-Liste" und wandel erst möglichst spät um.
Was würdet ihr machen?
Andere Frage: Der eigentliche BASIC-Code liegt grob in dieser Binären Form vor:
0x1e
0x00 <- Startmarkierung
0x?? <- Zeilennummer
...nun kommt eine Code Zeile...
0x00 <- Endmarkierung
0x1e
0x00 <- Startmarkierung
0x?? <- Zeilennummer
...Code Zeile...
0x00 <- Endmarkierung code zeile
0x00
0x00 <- zweimal 0x00 == Dateiende
Genauere Beschreibung hier:
http://dragon32.info/info/basicfmt.html
z.Z. iteriere ich über die Bytes, schaue nach den Marker-Bytes und verarbeite es mit einigen IF...ELSE Blöcken, siehe:
https://github.com/jedie/python-code-sn ... c12#L0R484
Wie kann man so was einfacher machen?
Denke das 'struct' Modul wäre was. Aber ich kann da nicht erkennen, wie man Daten mit variabler Länge verarbeiten kann.
Re: Dragon 32 Homecomputer Kassetten in ASCII umwandeln...
Verfasst: Samstag 17. August 2013, 23:03
von BlackJack
@jens: Ich würde versuchen die Zustandsvariablen zu vermeiden aus einem Byteiterator die Informationen ziehen, die man braucht. Also zum Beispiel in einem ersten Schritt den Bytestrom in einen Strom von Zeilen umwandeln. Und dann eine Funktion schreiben, die eine einzelne Zeile ausgibt.
Teil der Lösung könnte zum Beispiel so eine Funktion sein:
Code: Alles auswählen
def iter_tokenized_lines(bytestream):
while True:
next_line_pointer = bytestream.get_word()
if next_line_pointer == 0:
break
line_number = bytestream.get_word()
tokenized_line = bytestream.get_until('\x00')
yield (line_number, tokenized_line)
Re: Dragon 32 Homecomputer Kassetten in ASCII umwandeln...
Verfasst: Sonntag 18. August 2013, 14:31
von Leonidas
jens hat geschrieben:Hab gerade nochmal einen pull des aktuellen Stands gemacht:
https://github.com/jedie/python-code-sn ... 9b258cea6d
Hab ein BASIC token dict eingefügt, sieht so aus:
Code: Alles auswählen
BASIC_TOKENS = {
128: " FOR ", # 0x80
129: " GO ", # 0x81
130: " REM ", # 0x82
131: "'", # 0x83
132: " ELSE ", # 0x84
133: " IF ", # 0x85
...
Python hat auch Hex-Literale, die kann man auch bei Dicts als Schlüssel nutzen, dann spart man sich die seltsame Umrechnung und die Kommentare.
Re: Dragon 32 Homecomputer Kassetten in ASCII umwandeln...
Verfasst: Sonntag 18. August 2013, 16:43
von jens
Re: Dragon 32 Homecomputer Kassetten in ASCII umwandeln...
Verfasst: Sonntag 18. August 2013, 18:40
von jens
Hab nun verschiedene Beispiel-Wave Dateien mal getestet. Bekommt man u.a. hier her:
http://archive.worldofdragon.org/archiv ... ragon/wav/
Sind alle i.d.R. größere WAVE Dateien als meine beiden Beispiele... Dann merkt man doch schnell, das es langsam ist
Der Flaschenhals ist IMHO das umwandeln der WAVE Samles in nullen und einsen... Das kann man wiederrum in zwei Bereiche einteilen:
1. Das einlesen der WAV und erhalten der Sample-Werte
2. Das erkennen der nullen und einsen in den Sample-Werten
Mal Beispielwerte für eine WAVE Datei mit 5.151.803 audio samples:
Nr.1 dauert 1.5 sec
Nr.2 dauert 5.8 sec
Nr. 1 habe ich schon beschleunigt, in dem ich in größeren Blöcken
struct.unpack füttere. Die Zeit dazu ist vollkommen ok.
Nr. 2 dauert recht lange. Der Zuständige Code dazu:
Code: Alles auswählen
def samples2bits(samples, framerate, frame_count, even_odd):
in_positive = even_odd
in_negative = not even_odd
toggle_count = 0 # Counter for detect a complete cycle
previous_frame_no = 0
bit_count = 0
window_values = collections.deque(maxlen=MIN_TOGGLE_COUNT)
for frame_no, value in samples:
window_values.append(value)
if len(window_values) >= MIN_TOGGLE_COUNT:
positive_count, negative_count = count_sign(window_values)
# print window_values, positive_count, negative_count
if not in_positive and positive_count == MIN_TOGGLE_COUNT and negative_count == 0:
# go into a positive sinus area
in_positive = True
in_negative = False
toggle_count += 1
elif not in_negative and negative_count == MIN_TOGGLE_COUNT and positive_count == 0:
# go into a negative sinus area
in_negative = True
in_positive = False
toggle_count += 1
if toggle_count >= 2:
# a single sinus cycle complete
toggle_count = 0
frame_count = frame_no - previous_frame_no
hz = framerate / frame_count
dst_one = abs(ONE_HZ - hz)
dst_nul = abs(NUL_HZ - hz)
if dst_one < dst_nul:
bit_count += 1
yield 1
else:
bit_count += 1
yield 0
previous_frame_no = frame_no
(Kompletter code hier:
https://github.com/jedie/python-code-sn ... _decode.py )
Ideen das zu beschleunigen?
Btw. in PyPy dürfte das eigentlich viel schneller gehen, oder? Muß ich mal irgendwann testen
Eine Idee hätte ich noch: Eigentlich sind 44.1KHz Sampling Frequenz verschwendung. Es reicht auch die hälfte. Ich könnte also schon beim einlesen zwei Werte zusammen fassen oder zusammen fassen lassen.
Evtl.
audioop.ratecv() nutzten?
Evtl. kann ich mit
audioop.cross(fragment, width) was anfangen:
Return the number of zero crossings in the fragment passed as an argument.