Dragon 32 Homecomputer Kassetten in ASCII umwandeln...
- jens
- Python-Forum Veteran
- Beiträge: 8502
- Registriert: Dienstag 10. August 2004, 09:40
- Wohnort: duisburg
- Kontaktdaten:
So, mit https://github.com/jedie/PyDragon32/com ... 1c84c3b0a7 nutzte ich den "TextLeveMeter" vorgestellt hier: http://www.python-forum.de/viewtopic.php?f=11&t=32150
Damit kann man jetzt besser "sehen" was passiert. Dabei ist die Verkettung der Generatoren nun vom vorteil...
Sehen kann man dann sowas hier:

Damit kann man jetzt besser "sehen" was passiert. Dabei ist die Verkettung der Generatoren nun vom vorteil...
Sehen kann man dann sowas hier:
Code: Alles auswählen
| | * |
| | * |
| | * |
| | * |
| | * |
| | * |
| | * |
| * | |
| * | |
| * | |
| * | |
| * | |
| * | |
| * | |
| * | |
| | * |
| | * |
| | * |
| | * |
bit 1 at 1868 in 19Samples = 2321Hz
| | * |
| | * |
| | * |
| | * |
| | * |
| | * |
| | * |
| | * |
| | * |
| | * |
| | * |
| | * |
| | * |
| * | |
| * | |
| * | |
| * | |
| * | |
| * | |
| * | |
| * | |
| * | |
| * | |
| * | |
| * | |
| * | |
| * | |
| | * |
| | * |
bit 0 at 1897 in 29Samples = 1520Hz
| | * |
| | * |
| | * |
| | * |
| | * |
| | * |
| | * |
| * | |
| * | |
| * | |
| * | |
| * | |
| * | |
| * | |
| * | |
| | * |
| | * |
| | * |
| | * |
bit 1 at 1916 in 19Samples = 2321Hz

- jens
- Python-Forum Veteran
- Beiträge: 8502
- Registriert: Dienstag 10. August 2004, 09:40
- Wohnort: duisburg
- Kontaktdaten:
Komisch, bei manchen Dateien habe ich offensichtlich verkehre Vorzeichen aus den WAVE Daten. Das sieht dann z.B. so aus:

Code: Alles auswählen
==== go into positive sinus cycle ===============
bit 0 at 4432 in 33Samples = 1336Hz
| | * | value: 76 (3.0%)
| | * | value: 49 (5.0%)
| | * | value: 21 (12.0%)
| |* | value: 6 (42.0%)
| * | value: 3 (85.0%)
| | * | value: 11 (23.0%)
| | * | value: 29 (8.0%)
| | * | value: 57 (4.0%)
| | * | value: 85 (3.0%)
| | * | value: 85 (3.0%)
| * | | value: -125 (3.0%)
| * | | value: -113 (3.0%)
| * | | value: -94 (3.0%)
| * | | value: -77 (4.0%)
| * | | value: -63 (5.0%)
| * | | value: -49 (6.0%)
| * | | value: -36 (8.0%)
| * | | value: -22 (12.0%)
| * | | value: -14 (19.0%)
| *| | value: -7 (37.0%)
| *| | value: -5 (51.0%)
| *| | value: -5 (51.0%)
| *| | value: -7 (37.0%)
| * | | value: -14 (19.0%)
| * | | value: -21 (13.0%)
| * | | value: -34 (8.0%)
| * | | value: -46 (6.0%)
| * | | value: -60 (5.0%)
| * | | value: -74 (4.0%)
| * | | value: -90 (3.0%)
| * | | value: -110 (3.0%)
| | * | value: 126 (2.0%)
==== go into positive sinus cycle ===============
bit 0 at 4464 in 32Samples = 1378Hz
| | * | value: 112 (2.0%)
| | * | value: 93 (2.0%)
| | * | value: 76 (3.0%)
| | * | value: 62 (4.0%)
| | * | value: 49 (5.0%)
| | * | value: 35 (7.0%)
| | * | value: 21 (12.0%)
| | * | value: 13 (19.0%)
| |* | value: 6 (42.0%)
| * | value: 3 (85.0%)
| * | value: 3 (85.0%)
| |* | value: 4 (63.0%)
| | * | value: 11 (23.0%)
| | * | value: 18 (14.0%)
| | * | value: 29 (8.0%)
| | * | value: 43 (5.0%)
| | * | value: 57 (4.0%)
| | * | value: 71 (3.0%)
| | * | value: 85 (3.0%)
| | * | value: 105 (2.0%)
| | * | value: 105 (2.0%)
| * | | value: -125 (3.0%)
| * | | value: -94 (3.0%)
| * | | value: -63 (5.0%)
| * | | value: -36 (8.0%)
| * | | value: -14 (19.0%)
| *| | value: -5 (51.0%)
| *| | value: -7 (37.0%)
| * | | value: -21 (13.0%)
| * | | value: -46 (6.0%)
| * | | value: -74 (4.0%)
| * | | value: -110 (3.0%)
| | * | value: 112 (2.0%)
==== go into positive sinus cycle ===============
bit 0 at 4497 in 33Samples = 1336Hz

@jens: Das war ja genau der Grund warum Deine original aufgenommene WAV bei einem ersten Versuch funktioniert hat, die von xroar aber nicht. Ich habe mir dann mit der `audioop.bias()`-Funktion beholfen um das zu korrigieren. Sollte irgendwo in diesem mittlerweile ziemlich langen Thema stehen. 

- jens
- Python-Forum Veteran
- Beiträge: 8502
- Registriert: Dienstag 10. August 2004, 09:40
- Wohnort: duisburg
- Kontaktdaten:
Die Information bekommt man allerdings aus dem WAVE modul nicht raus, oder? Zumindest finde ich nichts dazu bei http://docs.python.org/2/library/wave.htmlSirius3 hat geschrieben:Neben 8, 16, 32bit gibt es eben noch signed und unsigned-Datentypen in WAVE-Files.
Ich mein wäre ja ein leichtes, das Vorzeichen umzudrehen, wenn man wüßte ob das nötig ist.
Stimmt. Allerdings würde ich gern auf audioop verzichten, wenn's geht.BlackJack hat geschrieben:Ich habe mir dann mit der `audioop.bias()`-Funktion beholfen um das zu korrigieren.
audioop ist ein binär modul, oder?
@jens: Wenn es kein Binärmodul wäre, dann wäre es wohl zu langsam. Zumindest in CPython.
- jens
- Python-Forum Veteran
- Beiträge: 8502
- Registriert: Dienstag 10. August 2004, 09:40
- Wohnort: duisburg
- Kontaktdaten:
Hab bei http://docs.python.org/2/library/audioo ... op.lin2lin was interessantes gefunden:
Das heißt doch aber auch, das ich einfach pauschal bei 8-bit waves 128 addieren kann.In some audio formats, such as .WAV files, 16 and 32 bit samples are signed, but 8 bit samples are unsigned. So when converting to 8 bit wide samples for these formats, you need to also add 128 to the result:
new_frames = audioop.lin2lin(frames, old_width, 1)
new_frames = audioop.bias(new_frames, 1, 128)
The same, in reverse, has to be applied when converting from 8 to 16 or 32 bit width samples.
@jens: Genau das habe ich in meine Code der hier irgendwo im Thema steht gemacht. Wenn Samplebreite 1 Byte dann mit `bias()` drauf addieren.
- jens
- Python-Forum Veteran
- Beiträge: 8502
- Registriert: Dienstag 10. August 2004, 09:40
- Wohnort: duisburg
- Kontaktdaten:
done: https://github.com/jedie/PyDragon32/com ... b3c4ee065f
ohne:
und mit:
ohne:
Code: Alles auswählen
| | * | value: 64 (3.0%)
| | * | value: 65 (3.0%)
| | * | value: 64 (3.0%)
| | * | value: 65 (3.0%)
| | * | value: 64 (3.0%)
| | * | value: 64 (3.0%)
| | * | value: 65 (3.0%)
| | * | value: 65 (3.0%)
| | * | value: 65 (3.0%)
| * | | value: -128 (2.0%)
| * | | value: -92 (3.0%)
| * | | value: -69 (4.0%)
| * | | value: -76 (4.0%)
| * | | value: -92 (3.0%)
| | * | value: 124 (2.0%)
==== go into positive sinus cycle ===============
| | * | value: 88 (2.0%)
| | * | value: 64 (3.0%)
| | * | value: 65 (3.0%)
| | * | value: 88 (2.0%)
| | * | value: 104 (2.0%)
| * | | value: -120 (3.0%)
| * | | value: -100 (3.0%)
| * | | value: -84 (4.0%)
| * | | value: -77 (4.0%)
| * | | value: -68 (4.0%)
| * | | value: -69 (4.0%)
| * | | value: -76 (4.0%)
| * | | value: -92 (3.0%)
| * | | value: -108 (3.0%)
| * | | value: -121 (3.0%)
| | * | value: 116 (2.0%)
Code: Alles auswählen
| * | | value: -64 (4.0%)
| * | | value: -63 (5.0%)
| * | | value: -64 (4.0%)
| * | | value: -63 (5.0%)
| * | | value: -64 (4.0%)
| * | | value: -64 (4.0%)
| * | | value: -63 (5.0%)
| * | | value: -63 (5.0%)
| * | | value: -63 (5.0%)
*** Have 1 samples skipped, because to lower amplitude.
| | * | value: 36 (7.0%)
==== go into positive sinus cycle ===============
| | * | value: 59 (4.0%)
| | * | value: 52 (4.0%)
| | * | value: 36 (7.0%)
| *| | value: -4 (64.0%)
| * | | value: -40 (7.0%)
| * | | value: -64 (4.0%)
| * | | value: -63 (5.0%)
| * | | value: -40 (7.0%)
| * | | value: -24 (11.0%)
| |* | value: 8 (31.0%)
| | * | value: 28 (9.0%)
==== go into positive sinus cycle ===============
bit 1 at 21 in 11Samples = 2004Hz
First bit is at: 21
enable half sinus scan
| | * | value: 44 (5.0%)
| | * | value: 51 (5.0%)
| | * | value: 60 (4.0%)
| | * | value: 59 (4.0%)
| | * | value: 52 (4.0%)
| | * | value: 36 (7.0%)
| | * | value: 20 (12.0%)
| |* | value: 7 (36.0%)
| * | | value: -12 (22.0%)
@jens: Also *ganz* genau steht es hier: http://hg.python.org/cpython/file/48259 ... oop.c#l957 
Im Fall von 8-Bit-Werten sollte es auf ``new_value = (old_value + 128) & 0xff`` hinaus laufen. Wobei `new_value` und `old_value` als ``unsigned`` betrachtet werden. Erst danach darf man `new_value` als ``signed`` interpretieren.

Im Fall von 8-Bit-Werten sollte es auf ``new_value = (old_value + 128) & 0xff`` hinaus laufen. Wobei `new_value` und `old_value` als ``unsigned`` betrachtet werden. Erst danach darf man `new_value` als ``signed`` interpretieren.
- jens
- Python-Forum Veteran
- Beiträge: 8502
- Registriert: Dienstag 10. August 2004, 09:40
- Wohnort: duisburg
- Kontaktdaten:
Das liefert nicht die erwarteten Werte. Das folgende allerdings schon:BlackJack hat geschrieben:new_value = (old_value + 128) & 0xff
Code: Alles auswählen
value = value % 0xff - 128
@jens: Ich habe ja extra geschrieben, dass man das auf als *unsigned* interpretierte Bytewerte anwenden muss. Da würde Deine Formel ja schon mal keinen Sinn ergeben, weil das ``value % 256`` bei unsigned Bytewerten eine Nullopration ist — egal was man für `value` einsetzt, es käme immer wieder `value` dabei heraus:
Wenn man es in reinem Python lösen wollte, ist es wahrscheinlich am einfachsten den Typ-Code für `array` oder `struct` zu ``unsigned byte`` zu ändern und dann einfach 127 von jedem Wert abzuziehen.
Code: Alles auswählen
In [7]: all(v % 256 == v for v in xrange(256))
Out[7]: True
- jens
- Python-Forum Veteran
- Beiträge: 8502
- Registriert: Dienstag 10. August 2004, 09:40
- Wohnort: duisburg
- Kontaktdaten:
Heute viel zu viel Zeit damit verbracht. Aber ich will es endlich mal benutzbar haben...
Aktueller Stand: https://github.com/jedie/PyDragon32/com ... 8f4dd87bac
Damit das Debuggen einfacher wird, hab ich nur schon Code da um aus einem ASCII BASIC Datei einen bitstream zu generieren. Wenn nun noch bitstream2wave da ist, dann wäre das auch schon fertig.
Eigentlich klappt das ganze schon ganz gut. Allerdings z.Z. nur richtig mit "HelloWorld1 xroar.wav"
Die anderen WAVES, funktionieren nur halb. Der Filename-Block ist ok, aber die eigentlichen Daten sind verfälscht.
Denke aber das liegt am WAVE2bitstream Teil und nicht später beim verwerten des Bitstreams.
Nun ist alles stark auf Generatoren ausgelegt. d.h. die WAVE Datei wird ausgelesen und alles komplett bis zum erzeugen der eigentlichen Python-Daten-Objekten geschieht "gleichzeitig"...
Ich hab mal eine separate "Config Klasse" angelegt: https://github.com/jedie/PyDragon32/blo ... configs.py
Theoretisch sollte man damit einfach auch andere Formate, wie halt C64 Datasette, unterstützten können.
Aktueller Stand: https://github.com/jedie/PyDragon32/com ... 8f4dd87bac
Damit das Debuggen einfacher wird, hab ich nur schon Code da um aus einem ASCII BASIC Datei einen bitstream zu generieren. Wenn nun noch bitstream2wave da ist, dann wäre das auch schon fertig.
Eigentlich klappt das ganze schon ganz gut. Allerdings z.Z. nur richtig mit "HelloWorld1 xroar.wav"
Die anderen WAVES, funktionieren nur halb. Der Filename-Block ist ok, aber die eigentlichen Daten sind verfälscht.
Denke aber das liegt am WAVE2bitstream Teil und nicht später beim verwerten des Bitstreams.
Nun ist alles stark auf Generatoren ausgelegt. d.h. die WAVE Datei wird ausgelesen und alles komplett bis zum erzeugen der eigentlichen Python-Daten-Objekten geschieht "gleichzeitig"...
Ich hab mal eine separate "Config Klasse" angelegt: https://github.com/jedie/PyDragon32/blo ... configs.py
Theoretisch sollte man damit einfach auch andere Formate, wie halt C64 Datasette, unterstützten können.
- jens
- Python-Forum Veteran
- Beiträge: 8502
- Registriert: Dienstag 10. August 2004, 09:40
- Wohnort: duisburg
- Kontaktdaten:
Schade, ich dachte der Datenmüll würde zustande kommen, weil ich nur einmal, am Anfang, einen Bit-Sync mache. Mit https://github.com/jedie/PyDragon32/com ... 0c39cbf656 mache ich jeweils vor einem neuen Block ein neuen Bit-Sync.
Das bringt allerdings keine Besserung.
Denke ich werde nochmal anders heran gehen und wirklich den Null-Durchgang der Sinus-Kurve Triggern. Ist eh besser, weil Lautstärke unabhängig.
Doch wie machen?
Einfach sahen, Null-Durchgang ist immer dann, wenn sich das Vorzeichen ändert wäre IMHO zu Störanfällig.
Ich denke über folgendes nach (pseudocode):
Mit anderen Worten: Nulldurchgang ist dann, wenn einige Werte Negativ waren, einige Werte egal (neg. oder pos.) und einige nächsten Werte Positiv sind.
Das bringt allerdings keine Besserung.
Denke ich werde nochmal anders heran gehen und wirklich den Null-Durchgang der Sinus-Kurve Triggern. Ist eh besser, weil Lautstärke unabhängig.
Doch wie machen?
Einfach sahen, Null-Durchgang ist immer dann, wenn sich das Vorzeichen ändert wäre IMHO zu Störanfällig.
Ich denke über folgendes nach (pseudocode):
Code: Alles auswählen
end_count = 3
mid_count = 2
previous_values = frame_values[:end_count] # e.g.: 123-----
mid_values = frame_values[end_count:end_count] # e.g.: ---45---
next_values = frame_values[-end_count:] # e.g.: -----678
if previous_values > 0 and next_values <0:
yield mid_time(mid_values)
@jens:
Wenn Du die Rohdaten vorverarbeitest, kannst Du jeden Vorzeichenwechsel als Nulldurchgang werten. Z.B. mit einem simplen Glättfilter als moving average der letzten 2 oder 3 Werte. Grössere Störungen lassen sich damit nicht bügeln, da helfen nur noch schwerere Geschütze.
Weiter oben hattest Du etwas zum Schmitttrigger geschrieben. Hattest Du das auch implementiert? Mit Kenntnis der Zielfrequenzen kannst Du doch eine simple Triggerfunktion schreiben.
Wenn Du die Rohdaten vorverarbeitest, kannst Du jeden Vorzeichenwechsel als Nulldurchgang werten. Z.B. mit einem simplen Glättfilter als moving average der letzten 2 oder 3 Werte. Grössere Störungen lassen sich damit nicht bügeln, da helfen nur noch schwerere Geschütze.
Weiter oben hattest Du etwas zum Schmitttrigger geschrieben. Hattest Du das auch implementiert? Mit Kenntnis der Zielfrequenzen kannst Du doch eine simple Triggerfunktion schreiben.
- jens
- Python-Forum Veteran
- Beiträge: 8502
- Registriert: Dienstag 10. August 2004, 09:40
- Wohnort: duisburg
- Kontaktdaten:
Das habe ich mir auch überlegt.jerch hat geschrieben:Z.B. mit einem simplen Glättfilter als moving average der letzten 2 oder 3 Werte.
Die Idee von vorhin war doch recht schnell implementiert: https://github.com/jedie/PyDragon32/com ... 9ef#L1R272
Siehe da, nun kommt auch was vernünftiges raus!
EDIT: Schmittriger mit Hysterese hatte ich auch mal, war aber nicht so richtig effektiv.
- jens
- Python-Forum Veteran
- Beiträge: 8502
- Registriert: Dienstag 10. August 2004, 09:40
- Wohnort: duisburg
- Kontaktdaten:
Hab es mal eingebaut: https://github.com/jedie/PyDragon32/com ... e2f#L1R323
Aber es ist besser das aus zu lassen. Also Witzlos. Oder ich hab was falsch gemacht.
Aber es ist besser das aus zu lassen. Also Witzlos. Oder ich hab was falsch gemacht.
- jens
- Python-Forum Veteran
- Beiträge: 8502
- Registriert: Dienstag 10. August 2004, 09:40
- Wohnort: duisburg
- Kontaktdaten:
Endlich ein cli mit https://github.com/jedie/PyDragon32/com ... 14c28e036f
Bsp.:
EDIT: Siehe auch: http://www.python-forum.de/viewtopic.php?f=1&t=32170
Code: Alles auswählen
usage: PyDC_cli.py [-h] [-v] [--verbosity {0,10,20,30,40,50}]
[--logfile {0,10,20,30,40,50}]
[--hz_variation HZ_VARIATION]
[--min_volume_ratio MIN_VOLUME_RATIO]
[--avg_count AVG_COUNT] [--end_count END_COUNT]
[--mid_count MID_COUNT]
src dst
Python dragon 32 converter
positional arguments:
src Source filename (.wav/.bas)
dst Destination filename (.wav/.bas)
optional arguments:
-h, --help show this help message and exit
-v, --version show program's version number and exit
--verbosity {0,10,20,30,40,50}
verbosity level to stdout (lower == more output!)
(default: 30)
--logfile {0,10,20,30,40,50}
verbosity level to log file (lower == more output!)
(default: 20)
--hz_variation HZ_VARIATION
How much Hz can signal scatter to match 1 or 0 bit ?
(default: 450)
--min_volume_ratio MIN_VOLUME_RATIO
percent volume to ignore sample (default: 5)
--avg_count AVG_COUNT
How many samples should be merged into a average
value? (default: 0)
--end_count END_COUNT
Sample count that must be pos/neg at once (default: 2)
--mid_count MID_COUNT
Sample count that can be around null (default: 1)
Code: Alles auswählen
~$ python PyDC_cli.py FooBar.wav FooBar.bas
EDIT: Siehe auch: http://www.python-forum.de/viewtopic.php?f=1&t=32170