diff --git a/.gitignore b/.gitignore index 268104a5..b1a39143 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,12 @@ .DS_Store *.o /sam +*.gcno +*.gcda +*.wav +*.html +*.lha +*.map +render000.c +render020.c + diff --git a/AF_readme b/AF_readme new file mode 100644 index 00000000..3752c4a0 --- /dev/null +++ b/AF_readme @@ -0,0 +1,231 @@ +18.11.2018 +---------- +sudo apt-get install libsdl1.2-dev +make + +sdl-config ist ein Programm, das die Parameter ausgibt, die dann im Makefile benutzt werden. + +sdl-config --cflags +-I/usr/include/SDL -D_GNU_SOURCE=1 -D_REENTRANT + +sdl-config --libs +-L/usr/lib/x86_64-linux-gnu -lSDL + +./sam -wav sam.wav My name is sam. +play sam.wav + +oder direkt + +./sam My name is sam. + + +Amiga +----- +Im Makefile erst mal das SDL-Zeug auskommentieren. -noixemul bei Compiler- und Linker-Flags! (newlib hat falsches argc !???) +make CC=~/opt/m68k-amigaos_24Oct18/bin/m68k-amigaos-gcc + +Das erzeugte Wav-File hat Endian-Fehler. Alles wird direkt geschrieben, ohne auf Endianes zu achten! + +20.11.2018 +---------- +* eigenes Makefile fuer Amiga (wegen -noixemul un anderer SDL-Einstellungen) +* make CC=~/opt/m68k-amigaos_14Nov18/bin/m68k-amigaos-gcc -f Makefile.amiga + +Fixed WriteWav() in main.c (changed endianess where necessary) +-> Amiga Executable works! + +enabled SDL. -> Funktioniert! +ABER: sam wird viel groesser. + +ohne SDL (gestripped) 44 kBytes +mit SDL (gestripped) 256 kBytes ! + +Der linkt alles moegliche ran, z.B. sind Youstick-Meldungen im Executable... + +24.11.2018 +---------- +Inzwischen geht alles mit eigenem SDL->Portaudio-Wrapper. +CTRL-C Behandlung feht noch. + +gcovr --object-directory=. -r . --html --html-details -o coverage.html + +25.11.2018 +---------- +Auf nackten Amigas is SAM sehr langsam! + +sam_old_render_O2 67564 ----rwed Heute 17:30:44 +sam_Os 57576 ----rwed Heute 17:30:41 +sam_O3 73528 ----rwed Heute 17:30:38 +sam_old_render_Os 57760 ----rwed Heute 17:30:36 +sam_O2 66800 ----rwed Heute 17:30:34 + +A2000 +8.Ram Disk:> ; sam_Os 49 +8.Ram Disk:> ; sam_O2 44 +8.Ram Disk:> ; sam_O3 41 +8.Ram Disk:> ; sam_old_render_Os 32 +8.Ram Disk:> ; sam_old_render_O2 30 +8.Ram Disk:> ; sam_old_render_O3 28 +8.Ram Disk:> ; +8.Ram Disk:> ; sam_O2 Hello, my name is sam. 1 2 3 4 5 6 7 8 9 0 +8.Ram Disk:> +8.Ram Disk:> + +A1200, no FastMem +sam_Os 15s +sam_O2 14s +sam_O3 14s +sam_old_render_Os 10s +sam_old_render_O2 8s +sam_old_render_O3 8s + +Die alte Renderfunktion mit multable und 4 Bit bekomme ich mit +git checkout 760786f13b79ddf5b519131925863181d224b839 src/RenderTabs.h +git checkout 760786f13b79ddf5b519131925863181d224b839 src/render.c + + +Profiling +,it -pg linken und uebersetzen +/home/osboxes/opt/m68k-amigaos_14Nov18/bin/m68k-amigaos-gprof sam | gprof2dot -n0 -e0 | dot -Tsvg -o output.svg +mirage output.svg & + +4.Dec.2018 +---------- +Die alten Versionen von RenderTabs.h und render.c jetzt wieder hergestellt wie am 25.11. getestet. +Damit steigt die Geschwindigkeit deutlich an. + +Neue Funktionen : 46 Sekunden +alte Funktionen : 30 Sekunden + +Fuer +gprof test | gprof2dot -n0 -e0 | dot -Tpng -o output2.png && mirage output2.png +(gemessen ohne Soundausgabe oder Wave-File-schreiben, compiliert mit -O2, -pg und auf WinUAE Cycleexact A500 getestet) + +5.Dec.2018 +---------- +In render.c gibt es mehrere Stellen, an denen BufferPos/50 berechnet wird. Bufferpos ist ein int. Das Dauert. Wenn ich testweise statt dessen Bufferpos >> 6 rechne, also /64, dann ist das Ergebnis zwar falsch, aber statt 30 Sekunden werden nur noch 10 Sekunden benoetigt! + +8.12.2018 +--------- +-msmall-code saves a few bytes 2k oder so. +-fbaserel spart 8k oder so, das Programm wird aber langsamer 12..13 Sekunden statt 10..11 Sekunden. +-resident bekomme ich nur compiliert, wenn ich __ctypes.c patche. Sonst passiert sam: .text reloc for __ctype_ is out of range: 00000000 +Aber auch mit patch stürzt das Programm immer ab. + +10.12.2018 +---------- +Demos fuer Amiga angepasst. Neues Verzeichnis demos_amiga + +11.12.2018 +---------- +Makefile geaendert. Alles ausser render.c wird mit -Os compiliert. rendr.c mit -O2. Alles mir -msamll-code. +SAM ist jetzt 59912 Bytes gross. + +* Portaudio: debug-code entfern. (getMilliseconds(), File +* Audiotask muss __saveds sein, wenn mit -fbaserel uebersetzt wird. +* Programm ist nicht GPL, entsprechenden Header in meinen Audiofiles entfernt. + +14.12.2018 +---------- +Render() und RenderSample() gibt es jetzt als 68000 und 68020 Version, die automatisch ausgewaehlt werden. guess_number.rexx gemacht. Portaudio warnings behoben. + +16.12.2018 +---------- +Resident geht jetzt. Vorschlag von Bebbo zum Weitergeben von A4 ueber np_Input bzw pr_CIS gemacht + +21.12.2018 +---------- +Stopwatch fuer genauere Zeitmessung + +inline von Output() bringt 1,4 Sekunden bei Hello, my name is sam. 1 2 3 4 5 6 7 8 9 0 +timeTable[5][8] bringt nochmal 0,13 Sekunden + +-> 10,77 Sekunden + +ASM-inline fuer SDivMod32 in OutPut 10,77 -> 10,09 Sekunden + +22.Dec.2018 +----------- +*327>>14, also *327/16384 statt durch 50 in Output(). Jetzt ca 7,74 Skunden! Deutlich besser als die ASM Variante. +-resident stuerzt ab, wenn mit meinem Debug-Define compiliert wird. Wird da was zu gross? Fehler im Compiler? +- Es scheint nicht resident zu sein, sondern -msmall-code, was zum Absturz fuehrt. +- 327U i der Multiplikation, sonst stuerzt sam bei langen Texten ab. +- Test fuer Linux und Amiga: sam Hello, my name is sam. 1 2 3 4 5 6 7 8 9 0 0 9 8 7 6 5 4 3 2 1 +Damit dann auch nochmal A1200 testen und dort ev fiv lassen? Dort ev anders optimieren? + +27.Dec.2018 +----------- +Der Code enthaelt viele globale Variablen, die ev. die Optimierung beeintraechtigen? + +Alle globalen Variablen finden + +~/opt/m68k-amigaos_23Dec18/bin/m68k-amigaos-gdb sam +info variables + +Dann die C-Files finden, in denen dieses Variablen benutzt werden. Manche koenen vielleicht zu lokalen Variablen gemacht werden. +z.B. finde alle Verwendungen von mem39 finden + +find src -name "*.c" -exec grep -nH "mem39[^(0-9)]" {} \; + + +28.Dec.28 +--------- +WinUAE +A1200 ohne FastRam: 1111ms (1286ms bei 68000-code) +A1200 mit FastRam: 423ms (474ms bei 68000-code) +Die 68020-Erkennung bringt also nicht wirklich viel... + +A500 ohne FastRam: 7572ms +A500 mit FastRam: 7569ms +Beim A500 spielt FastRam also keine Rolle. + +Sam Groesse: 49900 Bytes + +Aminet: +;http://aminet.net/util/arc/lha.run ; lha genommen: LhA 2.15 68000+ Jan 3 2011 +wget http://aminet.net/util/arc/lha.run + +in WinUAE: +protect demos_amiga/#? +s +protect sam +p +lha_68k a sam.lha sam sam.readme README.md +lha_68k a sam.lha demos_amiga/#? -r + +in Linux: +ftp -p # -p passive mode, falls ftp durch NAT +open main.aminet.net +Name (main.aminet.net:developer): anonymous +Password: selco@t-online.de +cd new +pwd +put sam.lha +put sam.readme # keine Verzeichnisse! also nicht z.B. amiga/espeak.readme! +quit + +Aminet Release 1.1 + +29.Dec.2018 +----------- +Kommentar von Gunther Nikl: +Anbei noch ein Patch für render2.c: Dort importierst Du sinus und +rectangle als "const". Diese sind in RenderTabs.h aber OHNE const +angelegt. + +--> const aus render2.c rausgenommen. 32 Bytes kleineres Programm. +Compiler vom 28.12.18 genommen. + + +1.Mar.2019 +---------- +Der gcc kann jetzt auch mit +make update +make v date=2019-02-18 +make all PREFIX=/here/or/there + +aufgerufen werden. dann wird (in alle Projekten) )ausgechecked, was am 18.Feb.2019 gueltig war. (auch, wenn es z.B. am 12.Jan. das letzte checkin/push gab) + + +15.Aug.2019 +----------- +Neues Target fuer Profiling. Der Linker hat gemeckert doppelte definitionen angemeckert. Anscheinend wird beim Profiling eine Variable mit dem Quellfilenamen angelegt. Bei uns wurde zwei mal render2.c benutz (fuer 68000 und 68020), damit gab es die Variable wohl doppelt. Deshalb kopiert das Makefile jetzt render2.c nach render000.c und render020.c und compiliert diese beiden temporaeren Quellen. Sie werden anschliessend geloescht. In .gitignore sind sie auch eingetragen. + diff --git a/Makefile b/Makefile index 5a622026..8a7c5f41 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -OBJS = reciter.o sam.o render.o main.o debug.o +OBJS = reciter.o sam.o render.o main.o debug.o endian.o CC = gcc diff --git a/Makefile.amiga b/Makefile.amiga new file mode 100644 index 00000000..44a8c679 --- /dev/null +++ b/Makefile.amiga @@ -0,0 +1,157 @@ +# All the o-Files in Link-Order +OBJS_ORDERED = reciter.o sam.o debug.o endian.o sdlwrapper.o portaudio_audev.o render.o render000.o render020.o main.o portaudio_ahidev.o portaudio.o subtask_support.o amiga_version.o stopwatch.o + +# 7.552 Seconds +# COMPILER_INSTALL_DIR ?= /home/developer/opt/m68k-amigaos_23Dec18 + # 7.58 Seconds for 21Jan19 +# bad COMPILER_INSTALL_DIR ?= /home/developer/opt/m68k-amigaos_21Jan19 +# OK COMPILER_INSTALL_DIR ?= /home/developer/opt/m68k-amigaos_29Dec18 +# bad COMPILER_INSTALL_DIR ?= /home/developer/opt/m68k-amigaos_14Jan19 +# bad COMPILER_INSTALL_DIR ?= /home/developer/opt/m68k-amigaos_13Jan19 +# ok COMPILER_INSTALL_DIR ?= /home/developer/opt/m68k-amigaos_09Jan19 +# OK --> COMPILER_INSTALL_DIR ?= /home/developer/opt/m68k-amigaos_11Jan19 +# ok COMPILER_INSTALL_DIR ?= /home/developer/opt/m68k-amigaos_06Jan19 +# bad, wird nicht fertig bei Coverage COMPILER_INSTALL_DIR ?= /home/developer/opt/m68k-amigaos_10Feb19 +# ok COMPILER_INSTALL_DIR ?= /home/developer/opt/m68k-amigaos_04Feb19 +# OK COMPILER_INSTALL_DIR ?= /home/developer/opt/m68k-amigaos_07Feb19 +# OK COMPILER_INSTALL_DIR ?= /home/developer/opt/m68k-amigaos_12Feb19 +# OK COMPILER_INSTALL_DIR ?= /home/developer/opt/m68k-amigaos_16Feb19 +# OK COMPILER_INSTALL_DIR ?= /home/developer/opt/m68k-amigaos_25Feb19 +# OK COMPILER_INSTALL_DIR ?= /home/developer/opt/m68k-amigaos_26Feb19 +# BAD, Linker Errors COMPILER_INSTALL_DIR ?= /home/developer/opt/m68k-amigaos_28Feb19 +# bad coverage failed (vamos illegal memory access) COMPILER_INSTALL_DIR ?= /home/developer/opt/m68k-amigaos_01Mar19 +# bad coverage failed (vamos illegal memory access) COMPILER_INSTALL_DIR ?= /home/developer/opt/m68k-amigaos_02Mar19 +# bad coverage failed (vamos illegal memory access) COMPILER_INSTALL_DIR ?= /home/developer/opt/m68k-amigaos_04Mar19 +# bad coverage failed (vamos illegal memory access) COMPILER_INSTALL_DIR ?= /home/developer/opt/m68k-amigaos_07Mar19 +# OK now again. Coverage works +# OK COMPILER_INSTALL_DIR ?= /home/developer/opt/m68k-amigaos_12Mar19 +# OK COMPILER_INSTALL_DIR ?= /home/developer/opt/m68k-amigaos_13Mar19 +# OK COMPILER_INSTALL_DIR ?= /home/developer/opt/m68k-amigaos_15Mar19 +# OK COMPILER_INSTALL_DIR ?= /home/developer/opt/m68k-amigaos_16Mar19 # changed include for SDL starting 16Mar19 +# OK COMPILER_INSTALL_DIR ?= /home/developer/opt/m68k-amigaos_17Mar19 +# OK COMPILER_INSTALL_DIR ?= /home/developer/opt/m68k-amigaos_18Mar19 +# OK COMPILER_INSTALL_DIR ?= /home/developer/opt/m68k-amigaos_21Mar19 +# OK COMPILER_INSTALL_DIR ?= /home/developer/opt/m68k-amigaos_23Mar19 +# OK COMPILER_INSTALL_DIR ?= /home/developer/opt/m68k-amigaos_02Apr19 +# BAD ld: internal error /home/developer/amiga-gcc_07Apr19/projects/binutils/ld/ldlang.c 6644 COMPILER_INSTALL_DIR ?= /home/developer/opt/m68k-amigaos_07Apr19 +# BAD ld: internal error /home/developer/amiga-gcc_08Apr19/projects/binutils/ld/ldlang.c 6644 COMPILER_INSTALL_DIR ?= /home/developer/opt/m68k-amigaos_08Apr19 +# BAD ld: internal error /home/developer/amiga-gcc_12Apr19/projects/binutils/ld/ldlang.c 6644 COMPILER_INSTALL_DIR ?= /home/developer/opt/m68k-amigaos_12Apr19 +# BAD ld: internal error /home/developer/amiga-gcc_13Apr19/projects/binutils/ld/ldlang.c 6644 COMPILER_INSTALL_DIR ?= /home/developer/opt/m68k-amigaos_13Apr19 +# BAD ld: internal error /home/developer/amiga-gcc_14Apr19/projects/binutils/ld/ldlang.c 6644COMPILER_INSTALL_DIR ?= /home/developer/opt/m68k-amigaos_14Apr19 +# BAD machine: ERROR COMPILER_INSTALL_DIR ?= /home/developer/opt/m68k-amigaos_15Apr19 +# BAD machine: ERROR COMPILER_INSTALL_DIR ?= /home/developer/opt/m68k-amigaos_16Apr19 +# BAD machine: ERROR COMPILER_INSTALL_DIR ?= /home/developer/opt/m68k-amigaos_23Apr19 +# OK COMPILER_INSTALL_DIR ?= /home/developer/opt/m68k-amigaos_28Apr19 +# OK COMPILER_INSTALL_DIR ?= /home/developer/opt/m68k-amigaos_01May19 +# OK COMPILER_INSTALL_DIR ?= /home/developer/opt/m68k-amigaos_07May19 +# OK COMPILER_INSTALL_DIR ?= /home/developer/opt/m68k-amigaos_18May19 +# OK COMPILER_INSTALL_DIR ?= /home/developer/opt/m68k-amigaos_26May19 +# OK COMPILER_INSTALL_DIR ?= /home/developer/opt/m68k-amigaos_30Jun19 +#COMPILER_INSTALL_DIR ?= /home/developer/opt/m68k-amigaos_07Aug19 +# BAD Coverage geht nicht mehr COMPILER_INSTALL_DIR ?= /home/developer/opt/m68k-amigaos_15Aug19 +# BAD Coverage geht nicht mehr COMPILER_INSTALL_DIR ?= /home/developer/opt/m68k-amigaos_18Aug19 +# BAD Coverage geht nicht mehr +COMPILER_INSTALL_DIR ?= /home/developer/opt/m68k-amigaos_20Aug19 + +COMPILER_DIR = $(COMPILER_INSTALL_DIR)/bin +CC = $(COMPILER_DIR)/m68k-amigaos-gcc #gcc +STRIP = $(COMPILER_DIR)/m68k-amigaos-strip +GCOV = $(COMPILER_DIR)/m68k-amigaos-gcov +GPROF = $(COMPILER_DIR)/m68k-amigaos-gprof + +TOOLCHAIN_VER=$(shell cat $(COMPILER_DIR)/toolchain_commit.txt) + +CPUFLAGS=-m68000 + +CFLAGS = -DDATE="\"$(shell /bin/date +'%d.%m.%Y')\"" +CFLAGS += -DPLATFORM_IS_BIG_ENDIAN -DSTATIC_FUNC= -DUSESDL +CFLAGS += -DTOOLCHAIN_VER="\"$(TOOLCHAIN_VER)\"" +CFLAGS += -DDEBUG +CFLAGS += -Iamiga/ -Iamiga/portaudio/ -I. +CFLAGS += -I$(COMPILER_INSTALL_DIR)/include/SDL # for toolchain up to 15Mar19 +CFLAGS += -I$(COMPILER_INSTALL_DIR)/m68k-amigaos/include/SDL # for toolchain starting 16Mar19 +CFLAGS += $(CPUFLAGS) +CFLAGS += -Os # all but render.c arecompiled for size. Only render.c will be compiled for speed +CFLAGS += -Wall -fomit-frame-pointer -noixemul -g #`sdl-config --cflags` + +CFLAGS += -resident +CFLAGS += -msmall-code + +LFLAGS = -g -noixemul $(CPUFLAGS) -Wl,-Map=sam.map,--trace -ldebug #-lSDL #`sdl-config --libs` +LFLAGS += -resident + +#coverage +ifneq ($(COVERAGE),) + CFLAGS += -fprofile-generate=VBox:$(shell pwd | cut -c2-) # remove first "/" from pwd -> VBox:home/... + CFLAGS += -ftest-coverage + CFLAGS += -fprofile-arcs #-pg # Profiler + LFLAGS += -lgcov +endif + +#profiling +ifneq ($(PROFILE),) +# CFLAGS += -fprofile-generate=VBox:$(shell pwd | cut -c2-) # remove first "/" from pwd -> VBox:home/... +# CFLAGS += -fprofile-arcs +# LFLAGS += -lgcov + CFLAGS += -g -pg -fno-omit-frame-pointer + LFLAGS += -pg +endif + + +vpath sdlwrapper.c src/amiga/ +vpath portaudio.c src/amiga/portaudio/ +vpath portaudio_ahidev.c src/amiga/portaudio/ +vpath portaudio_audev.c src/amiga/portaudio/ +vpath portaudio.c src/amiga/portaudio/ +vpath subtask_support.c src/amiga/portaudio/ +vpath amiga_version.c src/amiga/version/ +vpath stopwatch.c src/amiga/stopwatch/ + + +sam: $(OBJS_ORDERED) + $(CC) -o sam $(OBJS_ORDERED) $(LFLAGS) + ls -la sam + sync + +strip: sam + $(STRIP) $< + ls -la sam + sync + +render000.o: src/render2.c + cp src/render2.c src/render000.c + $(CC) $(CFLAGS) -O2 -c src/render000.c -o render000.o # this one is compiled with -O2 as it is the time critical part + rm src/render000.c + +render020.o: src/render2.c + cp src/render2.c src/render020.c + $(CC) $(CFLAGS) -m68020 -O2 -c src/render020.c -o render020.o # this one is compiled with -O2 as it is the time critical part + rm src/render020.c + +%.o: src/%.c + $(CC) $(CFLAGS) -c $< + +package: + tar -cvzf sam.tar.gz README.md Makefile sing src/ + +clean: + rm -f *.o *.wav sam sam.map *.gcno *.gcda *.gcov gmon.out coverage*.html src/render000.c src/render020.c + +coverage: + make -f Makefile.amiga COVERAGE=true + find | grep gcno | wc --w > count.txt # 15 gcno-Files should have been created + echo Found $$(cat count.txt) gcno-Files. + [ $$(cat count.txt) = "15" ] || (echo Wrong number of gcno-Files!; exit 1) + vamos -s 100 -V VBox:/home/developer/ -- sam -wav hello.wav "Hello, my name is sam. 1 2 3 4 5 6 7 8 9 0" # start sam, -s -> coverage needs more stack + $(GCOV) main.c + # argument-loop must have been ececuted 3 times in our example. Red if string not found (|| nothing) or count <3, green if all OK + cat main.c.gcov | (grep "while(i < argc)" || echo nothing) | awk -F: '{if( strtonum($$1) >=3){ print "\033[92mCoverage OK\033[0m";} else{ print "\033[91mCoverage failed!!!\033[0m"; exit 1;}}' + +profile: + make -f Makefile.amiga PROFILE=true + vamos -V VBox:/home/developer/ -- sam -wav hello.wav "Hello, my name is sam. 1 2 3 4 5 6 7 8 9 0" # start sam + ls -la gmon.out # check gmon.out has been created + $(GPROF) sam | awk '/RenderSample_000$$/{Count=$$4; if( strtonum(Count) ==55){ print "\033[92mProfile OK\033[0m";} else{ print "\033[91mProfile failed!!!\033[0m"; exit 1;}}' # profile output ok? RenderSample_000() should be called 55 times + +test: sam + vamos -v -V VBox:/home/developer/ -- sam -wav hello.wav "Hello, my name is sam. 1 2 3 4 5 6 7 8 9 0" # start sam diff --git a/demos_amiga/demo1 b/demos_amiga/demo1 new file mode 100755 index 00000000..215e7757 --- /dev/null +++ b/demos_amiga/demo1 @@ -0,0 +1,3 @@ + +/sam -debug "to bee or not to bee, that is the question"; +/sam -phonetic "MAY4 NEYM IHZ SAE4M."; diff --git a/demos_amiga/demo2 b/demos_amiga/demo2 new file mode 100755 index 00000000..e6d7c179 --- /dev/null +++ b/demos_amiga/demo2 @@ -0,0 +1,29 @@ + +/sam -pitch 64 -speed 72 -phonetic "/HEH4LOW DHEHR. YUW4 NOW MIY4Y, AY4 AEM SAE5M,"; +/sam -pitch 64 -speed 72 -phonetic "DHAH SAO4FTWEHR MAW5TH"; +/sam -pitch 64 -speed 72 -phonetic "FOHR YOHR KAA4MIXDOH6R SIH4KSTIYFOH6R KUMPYUW4TER."; +/sam -pitch 64 -speed 72 -phonetic "AY4 KUHD AO4LWEYZ DUW LAA3TS AHV AHMEY4ZIHNX THIHNXGZ."; +/sam -pitch 64 -speed 35 -phonetic "AY5 KUHD TAO5K VEH4RIY KWIH4KLIY WHEHN AY WAA4NTIHD."; +/sam -pitch 64 -speed 140 -phonetic "AE4ND AY KUHD TAO4K VEH3RIY SLOW4LIY TUW."; +/sam -pitch 30 -speed 72 -phonetic "AY5 KUHD SPIY5K IHNAH VEH3RIY /HAY5 VOYS."; +/sam -pitch 169 -speed 72 -phonetic "AE4ND AY KUHD SPIY5K RIY3L LOW."; +/sam -pitch 64 -speed 72 -phonetic "BAHT NAW4 AY KAEN DUW5 SAH4MPTHIHNX IY5VUN MOH4R AHMEY3ZIHNX."; + +/sam -mouth 110 -throat 160 -pitch 64 -speed 72 -phonetic "AY4 KAEN CHEY4NJ MAY VOY5S KUMPLIY3TLIY.Q."; +/sam -mouth 110 -throat 160 -pitch 64 -speed 72 -phonetic "AY4 KAEN BIY5 AH LIH4TUL EH5LF /HUW TAO5KS LAYK DHIH5S. OH3R."; + +/sam -mouth 190 -throat 190 -pitch 60 -speed 42 -phonetic "AY5 KAEN BIHKAH5M AH STREY4NJ EY4LIYUN."; +/sam -mouth 190 -throat 190 -pitch 60 -speed 42 -phonetic "YUW5 KAEN YUW4Z DHIHS VOY5S IHN AH SPEY4S GEY5M."; + +/sam -mouth 110 -throat 105 -pitch 72 -speed 82 -phonetic "OHR /HAW5 AHBAW5T DHIH3S STAH4FIY LIH5TUL KEH4RIXKTER."; +/sam -mouth 110 -throat 105 -pitch 72 -speed 82 -phonetic "EY SIH4LIY VOY5S FOHR AH KUMPYUW4TER."; + +/sam -mouth 145 -throat 145 -pitch 32 -speed 72 -phonetic "AY5 KAEN TAO5K LAYK AH LIH5TUL OH5LD LEY5DIY."; +/sam -mouth 145 -throat 145 -pitch 32 -speed 72 -phonetic "NAAT MEH5NIY KUMPYUW5TERZ KAEN DUW DHIH4S - SWIY5TIY."; + +/sam -mouth 128 -throat 128 -pitch 64 -speed 72 -phonetic "AE4ND AEZ AH MAE5TER AHV FAE4KT,"; +/sam -mouth 128 -throat 128 -pitch 64 -speed 72 -phonetic "AY4 KAEN BIYKAH5M DHAX LEY4TIXST MUW4VIY /HIY4ROW - AEND SEH8EY4,"; + +/sam -mouth 150 -throat 200 -pitch 58 -speed 120 -phonetic "IY4IY6 TTIY6 -FOW5N /HOW5MM. IY4IY6 TTIY6 - FOW5N /HOW5MM."; + +/sam -mouth 128 -throat 128 -pitch 64 -speed 72 -phonetic "DHEH4RZ NOW4 TEH5LIHNX WHAH5T SAE5M WIHL DUW NEH5KST."; diff --git a/demos_amiga/demo3 b/demos_amiga/demo3 new file mode 100755 index 00000000..9ea77bbb --- /dev/null +++ b/demos_amiga/demo3 @@ -0,0 +1,43 @@ + +/sam -pitch 64 -speed 74 -phonetic "/HEHLOW3 EH5VRIXWAHN. IHT SHUH4R IHZ NAY3S - TAX BIY /HIY4R TUH7DEY."; +/sam -pitch 64 -speed 74 -phonetic "AY3 AEM SAE4M -"; +/sam -pitch 64 -speed 74 -phonetic "DHAX BRAE4ND NUW5 VOY4S FOHR DHAX KAA4MIXDOH6R"; +/sam -pitch 64 -speed 74 -phonetic "SIH4KSTIYFOH6R KUMPYUW4TER."; +/sam -pitch 64 -speed 74 -phonetic "AY4 AEM DHAX MOW5ST VER4SIXTUL -"; +/sam -pitch 64 -speed 74 -phonetic "AH5NDERSTAE4NDIXBUL SPIY5CH SIH3NTHAXSAY7ZER"; +/sam -pitch 64 -speed 74 -phonetic "AAN DHAX MAA3RKIXT."; +/sam -pitch 64 -speed 74 -phonetic "AE4AE7ND- AY4 AEM DHAX LOHOW4EHST PRAY4ST- AHV DHEHM AO4UL."; +/sam -pitch 64 -speed 74 -phonetic "BAH6T WHAH4T KAEN YUW DUW3 WHIHTH MIYIY."; +/sam -pitch 64 -speed 74 -phonetic "WAY7 YUW3 KAEN PUH5T MIY-IH5NTUX YOHR OW7N PROH3GRAEMZ."; +/sam -pitch 64 -speed 74 -phonetic "/HAW4 WUHD YUW4 LAYK YOHR BIH3ZNIXS SAO5FTWEHR TUX SEY-"; +/sam -pitch 64 -speed 74 -phonetic "PLIY4Z EH5NTER DHIH4S WIY6KS PER3CHAHSIXZ."; +/sam -pitch 64 -speed 74 -phonetic "OH3ER- IHMAE3JIXN AEN EHDVEH4NCHER GEY6M DHAET DAH6Z DHIH4S."; +/sam -pitch 64 -speed 74 -phonetic "DHIY EH3LF WAHZ KAE3PCHERD-BAY DHAX JAY3IXNT."; +/sam -pitch 64 -speed 74 -phonetic "/HIY BIHGAE5N TUX KRAA3IY-AEND /HIY SEH4D."; + +/sam -pitch 31 -speed 72 -phonetic "OH5OW7 NAX5OW. PLIY5Z DOWNT /HER5T MIY-MIH6STER JAYIXNT?"; + +/sam -pitch 64 -speed 76 -phonetic "BAH6T DHAX JAY4IXNT WAHZ VEH3RIY MIY6N-"; +/sam -pitch 64 -speed 76 -phonetic "AEND /HIY4 OW3NLIY SEHD-"; + +/sam -pitch 120 -speed 80 -phonetic "/HOW2- /HOW4- /HOW."; + +/sam -pitch 64 -speed 72 -phonetic "DHEH5R IHZ NOW LIH3MIXT-TUX DHAX PAA4SAXBUL AE5PLIXKEY3SHUNZ-"; +/sam -pitch 64 -speed 72 -phonetic "AHV SPIY4CH IHN YOH7R PROH3GRAEMZ."; +/sam -pitch 64 -speed 72 -phonetic "AO3LSOW7W3- AY4 AEM VEH3RIY IY4ZIY TUX YUW4Z."; +/sam -pitch 64 -speed 72 -phonetic "EH2NIYWAH6N KAEN AE5DSPIY5CH-TUX6 AH BEY4SIHKQPROH4GRAEM."; +/sam -pitch 64 -speed 72 -phonetic "AY4 KAEN IY3VIXN TAOK VEH4RIY KWIH4KLIY."; +/sam -pitch 64 -speed 72 -phonetic "LIH4SUN TUX6 DHIH3S WAHN."; + +/sam -speed 30 -phonetic "PIY4TER PAY3PER- PIH4KT AH PEH4K AHV PIH4KULD PEH4PERZ."; + +/sam -speed 28 -phonetic "/HAW3 MEHNIY PEH4KS AHV PIH4KULD PEH4PERZ-DIHD PIY4TER PAY3PER PIH6K."; + +/sam -speed 100 -phonetic "QQQQ WWAW7IY1IY3IY. DHAE3T WHAHZ AH TAH4FIY."; + +/sam -speed 72 -phonetic "EH2NIYWEY6- YUW4 GEHT DHIY AYDIY5AH."; +/sam -speed 72 -phonetic "SAE3M IHZ DHIY MOW3STEHKSAY4TIHNX NUW4 PRAA4DAHKT - AHV DHIHS YIY4R."; +/sam -speed 72 -phonetic "SOH3OW7-/HAW4AHBAW3T IHT. WOH3NT YUW PLIY2Z TEY6KMIY /HOW6M?"; +/sam -speed 72 -phonetic "Q SAE4M IHZ /HIY3R TUX STEY4IY."; +/sam -speed 72 -phonetic "THAE2NXKS FOHR LIH4SUNIHNX EHVRIXBAH5DIY."; +/sam -speed 72 -phonetic "AY /HOW3P YUW EHNJOY4D-MAYLIH4TUL TAOK."; diff --git a/demos_amiga/demo4 b/demos_amiga/demo4 new file mode 100755 index 00000000..0573c616 --- /dev/null +++ b/demos_amiga/demo4 @@ -0,0 +1,7 @@ + +/sam "Four score and seven years ago."; +/sam "Our fathers brought forth on this continent, a new nation."; +/sam "Conceived in Libberty. And dedicated to the prop-position that all men are created equal."; + +/sam "Now we are engaged in a great civvil war! Testing whether that nation, or any nation."; +/sam "So conceived, and so dedicated, can long endure."; diff --git a/demos_amiga/demo5 b/demos_amiga/demo5 new file mode 100755 index 00000000..17155ac4 --- /dev/null +++ b/demos_amiga/demo5 @@ -0,0 +1,19 @@ + +/sam -mouth 110 -throat 160 -pitch 64 -speed 72 -phonetic "AY4 KAEN CHEY4NJ MAY VOY5S KUMPLIY3TLIY.Q."; + +/sam -mouth 150 -throat 200 -pitch 58 -speed 120 "Eee Tea! Phone home."; +/sam -mouth 150 -throat 200 -pitch 58 -speed 120 "Eee Tea? Phone home?"; + +/sam -mouth 150 -throat 200 -pitch 58 -speed 140 "Ha ha ha ha ha ha ha!"; +/sam -mouth 150 -throat 100 -pitch 58 -speed 140 "Ha ha ha ha ha ha ha?"; + +/sam -speed 140 -pitch 64 -throat 110 -mouth 160 "Ho ha ha ha!"; +/sam -speed 140 -pitch 60 -throat 190 -mouth 190 "Ha ha ha ha ha ha ha?"; + +/sam -speed 140 -pitch 72 -throat 110 -mouth 105 "He he ha ha he he ha!"; +/sam -speed 140 -pitch 32 -throat 145 -mouth 145 "Ha ha ho he he ha?"; + +/sam -speed 140 -pitch 64 -throat 150 -mouth 200 "Ha ha ho ho ha ho?"; +/sam -speed 35 -pitch 92 -throat 128 -mouth 128 "Ha ha ha ha ha ha ha? Ha ha ha ha ha ha ha!"; + +/sam "That's not funny."; diff --git a/demos_amiga/demo6 b/demos_amiga/demo6 new file mode 100755 index 00000000..0cf89483 --- /dev/null +++ b/demos_amiga/demo6 @@ -0,0 +1,105 @@ + +/sam "Hello my name is Sam."; +/sam "I will sing the national anthem of the United States of America."; +/sam "The Star Spangled Banner!"; +/sam -sing -speed 40 -pitch 64 -phonetic "ohohoh"; +/sam -sing -speed 40 -pitch 76 -phonetic "ohohoh"; +/sam -sing -speed 40 -pitch 96 -phonetic "sehehehehehehehehehey"; +/sam -sing -speed 40 -pitch 76 -phonetic "kaeaeaeaeaeaeaeaeaen"; +/sam -sing -speed 40 -pitch 64 -phonetic "yuxuxuxuxuxuxw"; +/sam -sing -speed 40 -pitch 48 -phonetic "siyiyiyiyiyiyiyiyiyiyiyiyiyiyiyiyiyiy"; +/sam -sing -speed 40 -pitch 38 -phonetic "baaaaay"; +/sam -sing -speed 40 -pitch 42 -phonetic "dhaaaxaxaxax"; +/sam -sing -speed 40 -pitch 48 -phonetic "daoaoaoaoaoaoaonz"; +/sam -sing -speed 40 -pitch 76 -phonetic "ererererererer"; +/sam -sing -speed 40 -pitch 68 -phonetic "liyiyiyiyiyiyiyiyiy"; +/sam -sing -speed 40 -pitch 64 -phonetic "laaaaaaaaaaaaaaaaaaaaaaaaayt"; +/sam -sing -speed 40 -pitch 64 -phonetic "whahahaht"; +/sam -sing -speed 40 -pitch 64 -phonetic "sohohuw"; +/sam -sing -speed 40 -pitch 38 -phonetic "praaaaaaaaaaaaaaaauwd"; +/sam -sing -speed 40 -pitch 42 -phonetic "liyiyiy"; +/sam -sing -speed 40 -pitch 48 -phonetic "wiyiyiyiyiyiyiyiyiy"; +/sam -sing -speed 40 -pitch 51 -phonetic "/heheheheheheheheheheheheheheheheheheyld"; +/sam -sing -speed 40 -pitch 56 -phonetic "aeaeaeaet"; +/sam -sing -speed 40 -pitch 51 -phonetic "dhaaaxaxaxax"; +/sam -sing -speed 40 -pitch 48 -phonetic "twaaaaaaaaaaaaaaiy"; +/sam -sing -speed 40 -pitch 48 -phonetic "laaaaaaaaaaaaiyts"; +/sam -sing -speed 40 -pitch 64 -phonetic "laeaeaeaeaeaeaeaeaest"; +/sam -sing -speed 40 -pitch 76 -phonetic "gliyiyiyiyiyiyiyiyiym"; +/sam -sing -speed 40 -pitch 96 -phonetic "mihihihihihihihihihihnx"; +/sam -sing -speed 40 -pitch 64 -phonetic "/huxuxuxuxuxuxuxuxuxuxwz"; +/sam -sing -speed 40 -pitch 76 -phonetic "braoaoaod"; +/sam -sing -speed 40 -pitch 96 -phonetic "straaaaaaaaaaaaiyps"; +/sam -sing -speed 40 -pitch 76 -phonetic "aeaeaeaeaeaeaeaeaeaend"; +/sam -sing -speed 40 -pitch 64 -phonetic "braaaaaaaaaaaaaaiyt"; +/sam -sing -speed 40 -pitch 48 -phonetic "staaaaaaaaaaaaaaaaaaaaaaaaaarz"; +/sam -sing -speed 40 -pitch 38 -phonetic "thruxuxw"; +/sam -sing -speed 40 -pitch 42 -phonetic "dhaaaxaxaxax"; +/sam -sing -speed 40 -pitch 48 -phonetic "pehehehehehehehehehehr"; +/sam -sing -speed 40 -pitch 76 -phonetic "rixixixixixixixixixixixixl"; +/sam -sing -speed 40 -pitch 68 -phonetic "lahahahahahahahahahs"; +/sam -sing -speed 40 -pitch 64 -phonetic "faaaaaaaaaaaaaaaaaaaaaaaaaaiyt"; +/sam -sing -speed 40 -pitch 64 -phonetic "ohohohr"; +/sam -sing -speed 40 -pitch 64 -phonetic "dhaaaxaxaxax"; +/sam -sing -speed 40 -pitch 38 -phonetic "raeaeaeaeaeaeaeaeaeaeaeaem"; +/sam -sing -speed 40 -pitch 42 -phonetic "paaaarts"; +/sam -sing -speed 40 -pitch 48 -phonetic "wiyiyiyiyiyiyiyiyiy"; +/sam -sing -speed 40 -pitch 51 -phonetic "waaaaaaaaaaaaaaaaaaaaaaaaaachd"; +/sam -sing -speed 40 -pitch 56 -phonetic "werer"; +/sam -sing -speed 40 -pitch 51 -phonetic "sohohw"; +/sam -sing -speed 40 -pitch 48 -phonetic "gaeaeaeaeaeaeaeaeaeael"; +/sam -sing -speed 40 -pitch 48 -phonetic "lixixixixixixixixixixixixixnt"; +/sam -sing -speed 40 -pitch 64 -phonetic "liyiyiyiyiyiyiyiyiy"; +/sam -sing -speed 40 -pitch 76 -phonetic "striyiyiyiyiyiyiyiyiym"; +/sam -sing -speed 40 -pitch 96 -phonetic "mihihihihihihihihihnx"; +/sam -sing -speed 40 -pitch 38 -phonetic "aeaeaeaeaend"; +/sam -sing -speed 40 -pitch 38 -phonetic "dhaaaxaxaxax"; +/sam -sing -speed 40 -pitch 38 -phonetic "raaaaaaaaaaaak"; +/sam -sing -speed 40 -pitch 36 -phonetic "kixixixixixixixixixixixts"; +/sam -sing -speed 40 -pitch 32 -phonetic "rehehehehehehehehehd"; +/sam -sing -speed 40 -pitch 32 -phonetic "gleheheheheheheheheheheheheheheherer"; +/sam -sing -speed 40 -pitch 36 -phonetic "dhaaaxaxaxax"; +/sam -sing -speed 40 -pitch 38 -phonetic "baaaamz"; +/sam -sing -speed 40 -pitch 42 -phonetic "bererererererst"; +/sam -sing -speed 40 -pitch 38 -phonetic "tihihihihihihihihihnx"; +/sam -sing -speed 40 -pitch 36 -phonetic "ihihihihihihihihihihn"; +/sam -sing -speed 40 -pitch 36 -phonetic "eheheheheheheheheheheheheheheheheheyr"; +/sam -sing -speed 40 -pitch 36 -phonetic "geheheheyv"; +/sam -sing -speed 40 -pitch 38 -phonetic "pruxuxuxuxuxuxuxuxuxuxuxuxwf"; +/sam -sing -speed 40 -pitch 42 -phonetic "thruxuxw"; +/sam -sing -speed 40 -pitch 48 -phonetic "dhaaaxaxax"; +/sam -sing -speed 40 -pitch 51 -phonetic "naaaaaaaaaaaaaaaaaaaaaaayiyt"; +/sam -sing -speed 40 -pitch 56 -phonetic "dhaeaeaeaet"; +/sam -sing -speed 40 -pitch 51 -phonetic "aaaaaauwr"; +/sam -sing -speed 40 -pitch 48 -phonetic "flaeaeaeaeaeaeaeaeaeg"; +/sam -sing -speed 40 -pitch 76 -phonetic "wahahahahahahahahahz"; +/sam -sing -speed 40 -pitch 68 -phonetic "stihihihihihihihihihl"; +/sam -sing -speed 40 -pitch 64 -phonetic "dhehehehehehehehehehehehehehehehehehehehr"; +/sam -sing -speed 40 -pitch 64 -phonetic "ohohohohohohow"; +/sam -sing -speed 40 -pitch 48 -phonetic "sehehehehehehehehehey"; +/sam -sing -speed 40 -pitch 48 -phonetic "dahahahahahahahahahz"; +/sam -sing -speed 40 -pitch 48 -phonetic "dhaeaeae"; +/sam -sing -speed 40 -pitch 51 -phonetic "aeaeaet"; +/sam -sing -speed 40 -pitch 56 -phonetic "staaaaaaaaaaaar"; +/sam -sing -speed 40 -pitch 56 -phonetic "spehehehehehehehehehiynx"; +/sam -sing -speed 40 -pitch 56 -phonetic "gaxaxaxaxaxaxaxaxaxaxaxaxld"; +/sam -sing -speed 40 -pitch 42 -phonetic "baeaeaeaeaeaeaeaeaen"; +/sam -sing -speed 40 -pitch 36 -phonetic "nerer"; +/sam -sing -speed 40 -pitch 38 -phonetic "ererer"; +/sam -sing -speed 40 -pitch 42 -phonetic "yeheheh"; +/sam -sing -speed 40 -pitch 48 -phonetic "eheheheht"; +/sam -sing -speed 40 -pitch 48 -phonetic "weheheheheheheheheheheh"; +/sam -sing -speed 40 -pitch 51 -phonetic "ehehehehehehehiyiyiyv"; +/sam -sing -speed 40 -pitch 64 -phonetic "ohohohr"; +/sam -sing -speed 40 -pitch 64 -phonetic "dhaaaxaxaxax"; +/sam -sing -speed 40 -pitch 48 -phonetic "laeaeaeaeaeaeaeaeaeaeaeae"; +/sam -sing -speed 40 -pitch 42 -phonetic "aeaeaend"; +/sam -sing -speed 40 -pitch 38 -phonetic "ahahahv"; +/sam -sing -speed 40 -pitch 36 -phonetic "dhaaaxaxaxax"; +/sam -sing -speed 40 -pitch 32 -phonetic "friyiyiyiyiyiyiyiyiyiyiyiyiyiyiyiyiyiy"; +/sam -sing -speed 40 -pitch 48 -phonetic "aeaeaend"; +/sam -sing -speed 40 -pitch 42 -phonetic "dhaaaxaxaxax"; +/sam -sing -speed 40 -pitch 38 -phonetic "/hohohohohohohohohowm"; +/sam -sing -speed 40 -pitch 36 -phonetic "ahahahahv"; +/sam -sing -speed 40 -pitch 42 -phonetic "dhaaaxaxaxaxaxaxaxaxaxaxaxaxax"; +/sam -sing -speed 40 -pitch 48 -phonetic "brehehehehehehehehehehiyiyiyv"; diff --git a/demos_amiga/demo7 b/demos_amiga/demo7 new file mode 100755 index 00000000..9770fbc5 --- /dev/null +++ b/demos_amiga/demo7 @@ -0,0 +1,6 @@ + +/sam -sing -pitch 96 -speed 50 "It's Jazzy Jazzy Jazzy"; +/sam -sing -pitch 68 -speed 50 "Jazzy Jazzy Jazzy"; +/sam -sing -pitch 48 -speed 50 "Jazzy Jazzy Jazzy"; +/sam -sing -pitch 32 -speed 50 "Jazzy Jazzy Jazzy"; +/sam -sing -pitch 96 -speed 50 "Jazzy"; diff --git a/demos_amiga/demo8 b/demos_amiga/demo8 new file mode 100755 index 00000000..0fb193cb --- /dev/null +++ b/demos_amiga/demo8 @@ -0,0 +1,11 @@ + +/sam "More than ever before. Americans are suff-er-ing from back, problems."; +/sam "Back. tach-sis."; +/sam "Back. rent?"; +/sam "Back. car payments."; +/sam "What we need is to get back. to the basics."; + +/sam "And say chilldren: What does it all mean."; + +/sam "And remember."; +/sam "If you want to see a comic strip? You should see me in the shouwer."; diff --git a/demos_amiga/demo9 b/demos_amiga/demo9 new file mode 100755 index 00000000..58dd9f3a --- /dev/null +++ b/demos_amiga/demo9 @@ -0,0 +1,16 @@ + +/sam -mouth 145 -throat 135 -pitch 40 -speed 72 -phonetic "AY5 KAEN TAO5K LAYK AH LIH5TUL OH5LD LEY5DIY.- SWIY5TIY."; + +/sam -mouth 145 -throat 125 -pitch 40 -speed 72 "You can do anything, but not everything."; +/sam -mouth 135 -throat 135 -pitch 35 -speed 72 "The richest man is not he who has the most. But he who wants the least."; +/sam -mouth 145 -throat 135 -pitch 40 -speed 72 "To the man who only has a hammer, everything he encounters looks like a nail."; +/sam -mouth 145 -throat 125 -pitch 35 -speed 72 "Before I got married I had six ideas about bringing up kids; now I have six kids. And no idea?"; +/sam -mouth 135 -throat 135 -pitch 40 -speed 72 "Always forgive your enemies. Nothing annoys them more."; +/sam -mouth 145 -throat 125 -pitch 35 -speed 72 "All people are frauds. The only difference between them is that some admit it. I myself totally dee-nigh. it."; +/sam -mouth 135 -throat 135 -pitch 40 -speed 72 "I do not mind what Con-gress does. As long as they do not do it. in the streets. And frighten the kids!"; + +/sam -speed 55 -pitch 92 -throat 128 -mouth 128 "Ha ha ha ha ha ha ha? Ha ha ha ha ha ha ha!"; +/sam "That's not funny grandma."; + +/sam -mouth 145 -throat 125 -pitch 40 -speed 72 "O.K. Let grandma take it from here."; +/sam -mouth 145 -throat 135 -pitch 40 -speed 72 -phonetic "SWIY5TIY."; diff --git a/demos_amiga/demoA b/demos_amiga/demoA new file mode 100755 index 00000000..00af1cb0 --- /dev/null +++ b/demos_amiga/demoA @@ -0,0 +1,6 @@ + +/sam -mouth 128 -throat 128 -pitch 64 -speed 72 -phonetic "/HEHLOH3OW. MAY4 NEY4M IHZ SAE4M."; +/sam -mouth 128 -throat 128 -pitch 64 -speed 72 -phonetic "AY4 EHM DHAX SAO4FTWEH4R SPIY4CH SIH3NTHAXSAY4ZER FOH4R DHAX KAA3MAXDOH4R KUMPYUWTER."; + +/sam -mouth 128 -throat 128 -pitch 64 -speed 72 -phonetic "AY4 PROWDUW3S /HAY4 KWAALAXTIY SPIY4CH FRAXM SIHMPAXL FAXNEHTIHK IH3NPUHT."; +/sam -mouth 128 -throat 128 -pitch 64 -speed 72 -phonetic "OH3R, AY4 KAEN TRAE3NZLEYT IYNGLIHSH DAXREHKTLIY TUH SPIYCH."; diff --git a/demos_amiga/demoB b/demos_amiga/demoB new file mode 100755 index 00000000..e0472ba2 --- /dev/null +++ b/demos_amiga/demoB @@ -0,0 +1,9 @@ + +/sam -mouth 128 -throat 128 -pitch 64 -speed 72 -phonetic "DHAX SOHLIHLAXKWIY FRAXM /HAE3MLEHT. BAY WIHLYAXM SHEY4KSPIHR."; +/sam -mouth 128 -throat 128 -pitch 64 -speed 72 -phonetic "TUH BIYIYIY2--OHR NAAT-TUH BIYIYIY."; +/sam -mouth 128 -throat 128 -pitch 64 -speed 72 -phonetic "DHAET IHZ THAX KWEHSCHAXN."; +/sam -mouth 128 -throat 128 -pitch 64 -speed 72 -phonetic "WEHDHER TIHZ NOHBLER IHN DHAX MAY4ND, TUH SAH4FER THAX SLIY3NGZ AEN3D"; +/sam -mouth 128 -throat 128 -pitch 64 -speed 72 -phonetic "EH4ROWZ AXV AWT REY3JAXS FOH4RCHAXN."; + +/sam -mouth 128 -throat 128 -pitch 64 -speed 72 -phonetic "OHR TUH TEYK AARMZ AXGEHNST AX4 SIY AXV TRAH4BAXLZ."; +/sam -mouth 128 -throat 128 -pitch 64 -speed 72 -phonetic "AEND BAY AHPOWZIHNG, EHND DHEHM."; diff --git a/demos_amiga/demoC b/demos_amiga/demoC new file mode 100755 index 00000000..ee7dae39 --- /dev/null +++ b/demos_amiga/demoC @@ -0,0 +1,13 @@ + +/sam -mouth 145 -throat 125 -pitch 40 -speed 72 "This is the original file extracted from the Commodore 64."; +/sam -mouth 145 -throat 125 -pitch 40 -speed 72 "O.K. ../sam. You can take it from here."; +/sam -mouth 145 -throat 135 -pitch 40 -speed 72 -phonetic "SWIY5TIY."; + +/sam -mouth 128 -throat 128 -pitch 64 -speed 72 -phonetic "AY4 WIHL NAW4 KWOWT-DHAX GEHTIYZBERG AXDREH3S."; +/sam -mouth 128 -throat 128 -pitch 64 -speed 72 -phonetic "FOH4R SKOH4R AEND SEHVIXN YIH3RZ AXGOW- AAR FAA3DHERZ BRAAT FOHRTH"; +/sam -mouth 128 -throat 128 -pitch 64 -speed 72 -phonetic "AXPAAN DHIHS KAANTIHNEHNT- EY NUH NEY4SHAXN."; +/sam -mouth 128 -throat 128 -pitch 64 -speed 72 -phonetic "KAHNSIYVD IHN LIH4BERTIY, AEND DEH4DIHKEYTIHD TUH DHAX PRAAPAXSIHSHAXN"; +/sam -mouth 128 -throat 128 -pitch 64 -speed 72 -phonetic "DHAET AAL MEHN AAR KRIYEY4TAXD IYKWUL."; +/sam -mouth 128 -throat 128 -pitch 64 -speed 72 -phonetic "NAW4 WIY AAR EHNGEYJD IHN DHAX GREYT SIHVAXL WOHR. TEHSTIHNG WEHDHER"; +/sam -mouth 128 -throat 128 -pitch 64 -speed 72 -phonetic "DHAE4T NEY4SHAXN, OHR EH4NIY NEYSHAXN SOH KAXNSIYVD AEND SOH"; +/sam -mouth 128 -throat 128 -pitch 64 -speed 72 -phonetic "DEH4DAHKEYTIHD, KAEN LAONX EHNDUH6UHR."; diff --git a/demos_amiga/demoD b/demos_amiga/demoD new file mode 100755 index 00000000..a474d199 --- /dev/null +++ b/demos_amiga/demoD @@ -0,0 +1,5 @@ + +/sam -mouth 128 -throat 128 -pitch 64 -speed 72 -phonetic "AY4 PLEHJ AXLIYJAXNS TUH DHAX FLAEG, AXV DHIY YUWNAYTEHD STEYTS"; +/sam -mouth 128 -throat 128 -pitch 64 -speed 72 -phonetic "AXV AXMEHRIYKAX. AEND TUH DHAX RIYPAHBLIHK FOHR WIHCH IHT STAENDZ."; +/sam -mouth 128 -throat 128 -pitch 64 -speed 72 -phonetic "WAHN NEYSHAXN AHNDER GAA5AA8D"; +/sam -mouth 128 -throat 128 -pitch 64 -speed 72 -phonetic "IHNDIHVIH4ZAXBAXL, WIHTH LIHBERTTIY, AEND JAH4STIHS- FOHR AAL."; diff --git a/demos_amiga/guess_number.rexx b/demos_amiga/guess_number.rexx new file mode 100755 index 00000000..621d06ee --- /dev/null +++ b/demos_amiga/guess_number.rexx @@ -0,0 +1,136 @@ +/* /start with "rx guess_number.rexx" */ +/* Adapted by AF, 14.Dec.2018 */ + +ADDLIB("rexxsupport.library",0, -30, 0) + +/* RANDOM() always delivers the same sequence, seems a varying seed is needed. */ +Seed=TIME(SECONDS) +SAY "Seed="Seed + +MAIN: /*:MAIN*/ +cls() +number=RANDOM(1,100,Seed) +/* rem goto WINNER */ +DELAY(50) +ECHO "Sam's NUMBER GUESSING GAME!" +ADDRESS COMMAND; "/SAM" "Sam's NUMBER GUESSING GAME!"; ADDRESS REXX +DELAY(50) +ECHO +DELAY(50) +ECHO +DELAY(50) +ECHO +DELAY(50) +ECHO "It's easy to play!" +ADDRESS COMMAND; "/SAM" "It's easy to play!"; ADDRESS REXX +DELAY(50) +ECHO +DELAY(50) +ECHO "The computer generates a number between 1 and 100, and you try to guess it!" +ADDRESS COMMAND; "/SAM" "The computer generates a number between 1 and 1 hundred, and you try to guess it!"; ADDRESS REXX +DELAY(50) +ECHO +DELAY(50) +ECHO +DELAY(50) +ECHO +ECHO "To begin the game, type your name and press Enter" +ADDRESS COMMAND; "/SAM" "To begin the game, type your name and press Enter"; ADDRESS REXX +PULL Name +HOME: +cls() +ECHO "Well" Name "Now GUESS THE NUMBER!" +ADDRESS COMMAND; "/SAM" "Well " Name ", now GUESS THE NUMBER!"; ADDRESS REXX +ECHO +ECHO +PULL guess +ECHO + +SELECT + WHEN guess < number THEN SIGNAL LOWER + WHEN guess > number THEN SIGNAL HIGHER + WHEN guess = number THEN SIGNAL WINNER +END + +LOWER: +cls() +ECHO "Your guess is lower than the number!" +ADDRESS COMMAND; "/SAM" "Your guess is lower than the number!"; ADDRESS REXX +ECHO +ECHO +pause +SIGNAL HOME + +HIGHER: +cls() +ECHO "Your guess is higher than the number!" +ADDRESS COMMAND; "/SAM" "Your guess is higher than the number!"; ADDRESS REXX +ECHO +ECHO +SIGNAL HOME + +WINNER: +cls() +ECHO +ADDRESS COMMAND; "/SAM" "-speed 55 -pitch 92 -throat 128 -mouth 128 " "Ha ha ha ha ha ha ha? Ha ha ha ha ha ha ha!"; ADDRESS REXX +ECHO "Congratulations " Name "! You guessed the number correctly!" +ADDRESS COMMAND; "/SAM" "Congratulations" Name "!"; ADDRESS REXX +ADDRESS COMMAND; "/SAM" "You guessed the number correctly!"; ADDRESS REXX +ECHO +ECHO +ECHO "The number was" number +ADDRESS COMMAND; "/SAM" "The number was" getNumberString(Number); ADDRESS REXX +ECHO "Thanks for playing " Name ",thanks for playing!" +ADDRESS COMMAND; "/SAM" "Thanks for playing?" Name "Thanks for playing."; ADDRESS REXX +DELAY(100) +EXIT + + +cls: PROCEDURE +ECHO "1B"x"[0;0H" "1B"x"[J" +RETURN 0 + + +getNumberString: PROCEDURE + ARG number + + SELECT + WHEN number < 10 THEN return number + + WHEN number = 10 THEN return "ten" + WHEN number = 11 THEN return "eleven" + WHEN number = 12 THEN return "twelve" + WHEN number = 13 THEN return "thirteen" + WHEN number = 14 THEN return "fourteen" + WHEN number = 15 THEN return "fifteen" + WHEN number = 16 THEN return "sixteen" + WHEN number = 17 THEN return "seventeen" + WHEN number = 18 THEN return "eighteen" + WHEN number = 19 THEN return "9teen" + + WHEN number = 20 THEN return "twenty" + WHEN number < 30 THEN return "twenty" || number//20 + + WHEN number = 30 THEN return "thirty" + WHEN number < 40 THEN return "thirty" || number//30 + + WHEN number = 40 THEN return "fourty" + WHEN number < 50 THEN return "fourty" || number//40 + + WHEN number = 50 THEN return "fifty" + WHEN number < 60 THEN return "fifty" || number//50 + + WHEN number = 60 THEN return "sixty" + WHEN number < 70 THEN return "sixty" || number//60 + + WHEN number = 70 THEN return "seventy" + WHEN number < 80 THEN return "seventy" || number//70 + + WHEN number = 80 THEN return "eighty" + WHEN number < 90 THEN return "eighty" || number//80 + + WHEN number = 90 THEN return "9tee" + WHEN number <100 THEN return "9tee" || number//90 + END + + diff --git a/sam.readme b/sam.readme new file mode 100644 index 00000000..86a3e919 --- /dev/null +++ b/sam.readme @@ -0,0 +1,41 @@ +Short: amiga-port of famous C64 speech synthesizer SAM +Author: sebastian@macke.de (Sebastian Macke) +Uploader: selco@t-online.de (Alexander Fritsch) +Type: util/sys +Version: 1.1 +Architecture: m68k-amigaos +Distribution: Aminet + + +This is the Amiga port of Sebastian Macke's great C-adaption of the +speech software SAM (Software Automatic Mouth) for the Commodore C64. +It creates a nice sounding voice directly from text. That sound can be +played via audio.device (default) or via ahi.device (-ahi unit). +The sound can also be saved to a wave-file. Input is possible in either +English text mode for automatic translation or in phoneme mode (-phonetic) + +Just enter sam to get a list of options. + +sam Hello, my name is sam. + +The program can be loaded resident to skip load times on further invocations. + +Resident sam PURE + +For a few more examples cd into demos_amiga drawer and enjoy the show. + +Resident sam PURE ; load sam only once +cd demos_amiga +execute demo1 +execute demo2 +; and so on... +; also try the tiny game +rx guess_number.rexx +Resident sam Remove + +Requirements: +Any Amiga will do. An 68000 is sufficient but an 68020 or better is utilized +if present. On a plain 7MHz 68000 it takes a few seconds to calculate until +sound occurs. Standard Amiga stack (4096) is sufficient. +Either audio.device or ahi.device is used for playback. + diff --git a/src/RenderTabs.h b/src/RenderTabs.h index 1dda2282..4989a869 100755 --- a/src/RenderTabs.h +++ b/src/RenderTabs.h @@ -1,69 +1,69 @@ #ifndef RENDERTABS_H #define RENDERTABS_H -const unsigned char tab48426[5] = { 0x18, 0x1A, 0x17, 0x17, 0x17 }; +unsigned char tab48426[5] = { 0x18, 0x1A, 0x17, 0x17, 0x17 }; -const unsigned char tab47492[] = +unsigned char tab47492[] = { - 0 , 0 , 0xE0 , 0xE6 , 0xEC , 0xF3 , 0xF9 , 0 , - 6 , 0xC , 6 + 0 , 0 , 0xE0 , 0xE6 , 0xEC , 0xF3 , 0xF9 , 0 , + 6 , 0xC , 6 }; -const unsigned char amplitudeRescale[] = +unsigned char amplitudeRescale[] = { - 0 , 1 , 2 , 2 , 2 , 3 , 3 , 4 , - 4 , 5 , 6 , 8 , 9 ,0xB ,0xD ,0xF, 0 //17 elements? + 0 , 1 , 2 , 2 , 2 , 3 , 3 , 4 , + 4 , 5 , 6 , 8 , 9 ,0xB ,0xD ,0xF, 0 //17 elements? }; // Used to decide which phoneme's blend lengths. The candidate with the lower score is selected. // tab45856 -const unsigned char blendRank[] = +unsigned char blendRank[] = { - 0 , 0x1F , 0x1F , 0x1F , 0x1F , 2 , 2 , 2 , - 2 , 2 , 2 , 2 , 2 , 2 , 5 , 5 , - 2 ,0xA , 2 , 8 , 5 , 5 ,0xB ,0xA , - 9 , 8 , 8 , 0xA0 , 8 , 8 , 0x17 , 0x1F , - 0x12 , 0x12 , 0x12 , 0x12 , 0x1E , 0x1E , 0x14 , 0x14 , - 0x14 , 0x14 , 0x17 , 0x17 , 0x1A , 0x1A , 0x1D , 0x1D , - 2 , 2 , 2 , 2 , 2 , 2 , 0x1A , 0x1D , - 0x1B , 0x1A , 0x1D , 0x1B , 0x1A , 0x1D , 0x1B , 0x1A , - 0x1D , 0x1B , 0x17 , 0x1D , 0x17 , 0x17 , 0x1D , 0x17 , - 0x17 , 0x1D , 0x17 , 0x17 , 0x1D , 0x17 , 0x17 , 0x17 + 0 , 0x1F , 0x1F , 0x1F , 0x1F , 2 , 2 , 2 , + 2 , 2 , 2 , 2 , 2 , 2 , 5 , 5 , + 2 ,0xA , 2 , 8 , 5 , 5 ,0xB ,0xA , + 9 , 8 , 8 , 0xA0 , 8 , 8 , 0x17 , 0x1F , + 0x12 , 0x12 , 0x12 , 0x12 , 0x1E , 0x1E , 0x14 , 0x14 , + 0x14 , 0x14 , 0x17 , 0x17 , 0x1A , 0x1A , 0x1D , 0x1D , + 2 , 2 , 2 , 2 , 2 , 2 , 0x1A , 0x1D , + 0x1B , 0x1A , 0x1D , 0x1B , 0x1A , 0x1D , 0x1B , 0x1A , + 0x1D , 0x1B , 0x17 , 0x1D , 0x17 , 0x17 , 0x1D , 0x17 , + 0x17 , 0x1D , 0x17 , 0x17 , 0x1D , 0x17 , 0x17 , 0x17 }; // Number of frames at the end of a phoneme devoted to interpolating to next phoneme's final value //tab45696 -const unsigned char outBlendLength[] = +unsigned char outBlendLength[] = { - 0 , 2 , 2 , 2 , 2 , 4 , 4 , 4 , - 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , - 4 , 4 , 3 , 2 , 4 , 4 , 2 , 2 , - 2 , 2 , 2 , 1 , 1 , 1 , 1 , 1 , - 1 , 1 , 1 , 1 , 1 , 1 , 2 , 2 , - 2 , 1 , 0 , 1 , 0 , 1 , 0 , 5 , - 5 , 5 , 5 , 5 , 4 , 4 , 2 , 0 , - 1 , 2 , 0 , 1 , 2 , 0 , 1 , 2 , - 0 , 1 , 2 , 0 , 2 , 2 , 0 , 1 , - 3 , 0 , 2 , 3 , 0 , 2 , 0xA0 , 0xA0 + 0 , 2 , 2 , 2 , 2 , 4 , 4 , 4 , + 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , + 4 , 4 , 3 , 2 , 4 , 4 , 2 , 2 , + 2 , 2 , 2 , 1 , 1 , 1 , 1 , 1 , + 1 , 1 , 1 , 1 , 1 , 1 , 2 , 2 , + 2 , 1 , 0 , 1 , 0 , 1 , 0 , 5 , + 5 , 5 , 5 , 5 , 4 , 4 , 2 , 0 , + 1 , 2 , 0 , 1 , 2 , 0 , 1 , 2 , + 0 , 1 , 2 , 0 , 2 , 2 , 0 , 1 , + 3 , 0 , 2 , 3 , 0 , 2 , 0xA0 , 0xA0 }; // Number of frames at beginning of a phoneme devoted to interpolating to phoneme's final value // tab45776 -const unsigned char inBlendLength[] = +unsigned char inBlendLength[] = { - 0 , 2 , 2 , 2 , 2 , 4 , 4 , 4 , - 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , - 4 , 4 , 3 , 3 , 4 , 4 , 3 , 3 , - 3 , 3 , 3 , 1 , 2 , 3 , 2 , 1 , - 3 , 3 , 3 , 3 , 1 , 1 , 3 , 3 , - 3 , 2 , 2 , 3 , 2 , 3 , 0 , 0 , - 5 , 5 , 5 , 5 , 4 , 4 , 2 , 0 , - 2 , 2 , 0 , 3 , 2 , 0 , 4 , 2 , - 0 , 3 , 2 , 0 , 2 , 2 , 0 , 2 , - 3 , 0 , 3 , 3 , 0 , 3 , 0xB0 , 0xA0 + 0 , 2 , 2 , 2 , 2 , 4 , 4 , 4 , + 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , + 4 , 4 , 3 , 3 , 4 , 4 , 3 , 3 , + 3 , 3 , 3 , 1 , 2 , 3 , 2 , 1 , + 3 , 3 , 3 , 3 , 1 , 1 , 3 , 3 , + 3 , 2 , 2 , 3 , 2 , 3 , 0 , 0 , + 5 , 5 , 5 , 5 , 4 , 4 , 2 , 0 , + 2 , 2 , 0 , 3 , 2 , 0 , 4 , 2 , + 0 , 3 , 2 , 0 , 2 , 2 , 0 , 2 , + 3 , 0 , 3 , 3 , 0 , 3 , 0xB0 , 0xA0 }; @@ -85,7 +85,7 @@ const unsigned char inBlendLength[] = // 67: ** 27 00011011 // 70: ** 25 00011001 // tab45936 -const unsigned char sampledConsonantFlags[] = +unsigned char sampledConsonantFlags[] = { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , @@ -103,338 +103,407 @@ const unsigned char sampledConsonantFlags[] = //tab45056 unsigned char freq1data[]= { - 0x00 ,0x13 ,0x13 ,0x13 ,0x13 , 0xA , 0xE ,0x12 - , 0x18 ,0x1A ,0x16 ,0x14 ,0x10 ,0x14 , 0xE ,0x12 - , 0xE ,0x12 ,0x12 ,0x10 , 0xC , 0xE , 0xA ,0x12 - , 0xE ,0xA , 8 , 6 , 6 , 6 , 6 ,0x11 - , 6 , 6 , 6 , 6 ,0xE , 0x10 , 9 ,0xA - , 8 ,0xA , 6 , 6 , 6 , 5 , 6 , 0 - , 0x12 , 0x1A , 0x14 , 0x1A , 0x12 ,0xC , 6 , 6 - , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 - , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 - , 6 ,0xA ,0xA , 6 , 6 , 6 , 0x2C , 0x13 + 0x00 ,0x13 ,0x13 ,0x13 ,0x13 , 0xA , 0xE ,0x12 + , 0x18 ,0x1A ,0x16 ,0x14 ,0x10 ,0x14 , 0xE ,0x12 + , 0xE ,0x12 ,0x12 ,0x10 , 0xC , 0xE , 0xA ,0x12 + , 0xE ,0xA , 8 , 6 , 6 , 6 , 6 ,0x11 + , 6 , 6 , 6 , 6 ,0xE , 0x10 , 9 ,0xA + , 8 ,0xA , 6 , 6 , 6 , 5 , 6 , 0 + , 0x12 , 0x1A , 0x14 , 0x1A , 0x12 ,0xC , 6 , 6 + , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 + , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 + , 6 ,0xA ,0xA , 6 , 6 , 6 , 0x2C , 0x13 }; //tab451356 unsigned char freq2data[]= { - 0x00 , 0x43 , 0x43 , 0x43 , 0x43 , 0x54 , 0x48 , 0x42 , - 0x3E , 0x28 , 0x2C , 0x1E , 0x24 , 0x2C , 0x48 , 0x30 , - 0x24 , 0x1E , 0x32 , 0x24 , 0x1C , 0x44 , 0x18 , 0x32 , - 0x1E , 0x18 , 0x52 , 0x2E , 0x36 , 0x56 , 0x36 , 0x43 , - 0x49 , 0x4F , 0x1A , 0x42 , 0x49 , 0x25 , 0x33 , 0x42 , - 0x28 , 0x2F , 0x4F , 0x4F , 0x42 , 0x4F , 0x6E , 0x00 , - 0x48 , 0x26 , 0x1E , 0x2A , 0x1E , 0x22 , 0x1A , 0x1A , - 0x1A , 0x42 , 0x42 , 0x42 , 0x6E , 0x6E , 0x6E , 0x54 , - 0x54 , 0x54 , 0x1A , 0x1A , 0x1A , 0x42 , 0x42 , 0x42 , - 0x6D , 0x56 , 0x6D , 0x54 , 0x54 , 0x54 , 0x7F , 0x7F + 0x00 , 0x43 , 0x43 , 0x43 , 0x43 , 0x54 , 0x48 , 0x42 , + 0x3E , 0x28 , 0x2C , 0x1E , 0x24 , 0x2C , 0x48 , 0x30 , + 0x24 , 0x1E , 0x32 , 0x24 , 0x1C , 0x44 , 0x18 , 0x32 , + 0x1E , 0x18 , 0x52 , 0x2E , 0x36 , 0x56 , 0x36 , 0x43 , + 0x49 , 0x4F , 0x1A , 0x42 , 0x49 , 0x25 , 0x33 , 0x42 , + 0x28 , 0x2F , 0x4F , 0x4F , 0x42 , 0x4F , 0x6E , 0x00 , + 0x48 , 0x26 , 0x1E , 0x2A , 0x1E , 0x22 , 0x1A , 0x1A , + 0x1A , 0x42 , 0x42 , 0x42 , 0x6E , 0x6E , 0x6E , 0x54 , + 0x54 , 0x54 , 0x1A , 0x1A , 0x1A , 0x42 , 0x42 , 0x42 , + 0x6D , 0x56 , 0x6D , 0x54 , 0x54 , 0x54 , 0x7F , 0x7F }; //tab45216 unsigned char freq3data[]= { - 0x00 , 0x5B , 0x5B , 0x5B , 0x5B , 0x6E , 0x5D , 0x5B , - 0x58 , 0x59 , 0x57 , 0x58 , 0x52 , 0x59 , 0x5D , 0x3E , - 0x52 , 0x58 , 0x3E , 0x6E , 0x50 , 0x5D , 0x5A , 0x3C , - 0x6E , 0x5A , 0x6E , 0x51 , 0x79 , 0x65 , 0x79 , 0x5B , - 0x63 , 0x6A , 0x51 , 0x79 , 0x5D , 0x52 , 0x5D , 0x67 , - 0x4C , 0x5D , 0x65 , 0x65 , 0x79 , 0x65 , 0x79 , 0x00 , - 0x5A , 0x58 , 0x58 , 0x58 , 0x58 , 0x52 , 0x51 , 0x51 , - 0x51 , 0x79 , 0x79 , 0x79 , 0x70 , 0x6E , 0x6E , 0x5E , - 0x5E , 0x5E , 0x51 , 0x51 , 0x51 , 0x79 , 0x79 , 0x79 , - 0x65 , 0x65 , 0x70 , 0x5E , 0x5E , 0x5E , 0x08 , 0x01 + 0x00 , 0x5B , 0x5B , 0x5B , 0x5B , 0x6E , 0x5D , 0x5B , + 0x58 , 0x59 , 0x57 , 0x58 , 0x52 , 0x59 , 0x5D , 0x3E , + 0x52 , 0x58 , 0x3E , 0x6E , 0x50 , 0x5D , 0x5A , 0x3C , + 0x6E , 0x5A , 0x6E , 0x51 , 0x79 , 0x65 , 0x79 , 0x5B , + 0x63 , 0x6A , 0x51 , 0x79 , 0x5D , 0x52 , 0x5D , 0x67 , + 0x4C , 0x5D , 0x65 , 0x65 , 0x79 , 0x65 , 0x79 , 0x00 , + 0x5A , 0x58 , 0x58 , 0x58 , 0x58 , 0x52 , 0x51 , 0x51 , + 0x51 , 0x79 , 0x79 , 0x79 , 0x70 , 0x6E , 0x6E , 0x5E , + 0x5E , 0x5E , 0x51 , 0x51 , 0x51 , 0x79 , 0x79 , 0x79 , + 0x65 , 0x65 , 0x70 , 0x5E , 0x5E , 0x5E , 0x08 , 0x01 }; -const unsigned char ampl1data[] = +unsigned char ampl1data[] = { - 0 , 0 , 0 , 0 , 0 ,0xD ,0xD ,0xE , - 0xF ,0xF ,0xF ,0xF ,0xF ,0xC ,0xD ,0xC , - 0xF ,0xF ,0xD ,0xD ,0xD ,0xE ,0xD ,0xC , - 0xD ,0xD ,0xD ,0xC , 9 , 9 , 0 , 0 , - 0 , 0 , 0 , 0 , 0 , 0 ,0xB ,0xB , - 0xB ,0xB , 0 , 0 , 1 ,0xB , 0 , 2 , - 0xE ,0xF ,0xF ,0xF ,0xF ,0xD , 2 , 4 , - 0 , 2 , 4 , 0 , 1 , 4 , 0 , 1 , - 4 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , - 0 ,0xC , 0 , 0 , 0 , 0 ,0xF ,0xF + 0 , 0 , 0 , 0 , 0 ,0xD ,0xD ,0xE , + 0xF ,0xF ,0xF ,0xF ,0xF ,0xC ,0xD ,0xC , + 0xF ,0xF ,0xD ,0xD ,0xD ,0xE ,0xD ,0xC , + 0xD ,0xD ,0xD ,0xC , 9 , 9 , 0 , 0 , + 0 , 0 , 0 , 0 , 0 , 0 ,0xB ,0xB , + 0xB ,0xB , 0 , 0 , 1 ,0xB , 0 , 2 , + 0xE ,0xF ,0xF ,0xF ,0xF ,0xD , 2 , 4 , + 0 , 2 , 4 , 0 , 1 , 4 , 0 , 1 , + 4 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , + 0 ,0xC , 0 , 0 , 0 , 0 ,0xF ,0xF }; -const unsigned char ampl2data[] = +unsigned char ampl2data[] = { - 0 , 0 , 0 , 0 , 0 ,0xA ,0xB ,0xD , - 0xE ,0xD ,0xC ,0xC ,0xB , 9 ,0xB ,0xB , - 0xC ,0xC ,0xC , 8 , 8 ,0xC , 8 ,0xA , - 8 , 8 ,0xA , 3 , 9 , 6 , 0 , 0 , - 0 , 0 , 0 , 0 , 0 , 0 , 3 , 5 , - 3 , 4 , 0 , 0 , 0 , 5 ,0xA , 2 , - 0xE ,0xD ,0xC ,0xD ,0xC , 8 , 0 , 1 , - 0 , 0 , 1 , 0 , 0 , 1 , 0 , 0 , - 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , - 0 ,0xA , 0 , 0 ,0xA , 0 , 0 , 0 + 0 , 0 , 0 , 0 , 0 ,0xA ,0xB ,0xD , + 0xE ,0xD ,0xC ,0xC ,0xB , 9 ,0xB ,0xB , + 0xC ,0xC ,0xC , 8 , 8 ,0xC , 8 ,0xA , + 8 , 8 ,0xA , 3 , 9 , 6 , 0 , 0 , + 0 , 0 , 0 , 0 , 0 , 0 , 3 , 5 , + 3 , 4 , 0 , 0 , 0 , 5 ,0xA , 2 , + 0xE ,0xD ,0xC ,0xD ,0xC , 8 , 0 , 1 , + 0 , 0 , 1 , 0 , 0 , 1 , 0 , 0 , + 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , + 0 ,0xA , 0 , 0 ,0xA , 0 , 0 , 0 }; -const unsigned char ampl3data[] = +unsigned char ampl3data[] = { - 0 , 0 , 0 , 0 , 0 , 8 , 7 , 8 , - 8 , 1 , 1 , 0 , 1 , 0 , 7 , 5 , - 1 , 0 , 6 , 1 , 0 , 7 , 0 , 5 , - 1 , 0 , 8 , 0 , 0 , 3 , 0 , 0 , - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , - 0 , 0 , 0 , 0 , 0 , 1 ,0xE , 1 , - 9 , 1 , 0 , 1 , 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , - 0 , 7 , 0 , 0 , 5 , 0 , 0x13 , 0x10 + 0 , 0 , 0 , 0 , 0 , 8 , 7 , 8 , + 8 , 1 , 1 , 0 , 1 , 0 , 7 , 5 , + 1 , 0 , 6 , 1 , 0 , 7 , 0 , 5 , + 1 , 0 , 8 , 0 , 0 , 3 , 0 , 0 , + 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , + 0 , 0 , 0 , 0 , 0 , 1 ,0xE , 1 , + 9 , 1 , 0 , 1 , 0 , 0 , 0 , 0 , + 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , + 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , + 0 , 7 , 0 , 0 , 5 , 0 , 0x13 , 0x10 }; //tab42240 -const signed char sinus[256] = -{0,3,6,9,12,16,19,22,25,28,31,34,37,40,43,46,49,51,54,57,60,63,65,68,71,73,76,78,81,83,85,88,90,92,94,96,98,100,102,104,106,107,109,111,112,113,115,116,117,118,120,121,122,122,123,124,125,125,126,126,126,127,127,127,127,127,127,127,126,126,126,125,125,124,123,122,122,121,120,118,117,116,115,113,112,111,109,107,106,104,102,100,98,96,94,92,90,88,85,83,81,78,76,73,71,68,65,63,60,57,54,51,49,46,43,40,37,34,31,28,25,22,19,16,12,9,6,3,0,-3,-6,-9,-12,-16,-19,-22,-25,-28,-31,-34,-37,-40,-43,-46,-49,-51,-54,-57,-60,-63,-65,-68,-71,-73,-76,-78,-81,-83,-85,-88,-90,-92,-94,-96,-98,-100,-102,-104,-106,-107,-109,-111,-112,-113,-115,-116,-117,-118,-120,-121,-122,-122,-123,-124,-125,-125,-126,-126,-126,-127,-127,-127,-127,-127,-127,-127,-126,-126,-126,-125,-125,-124,-123,-122,-122,-121,-120,-118,-117,-116,-115,-113,-112,-111,-109,-107,-106,-104,-102,-100,-98,-96,-94,-92,-90,-88,-85,-83,-81,-78,-76,-73,-71,-68,-65,-63,-60,-57,-54,-51,-49,-46,-43,-40,-37,-34,-31,-28,-25,-22,-19,-16,-12,-9,-6,-3}; +unsigned char sinus[] = +{ + 0x00 , 0x00 , 0x00 , 0x10 , 0x10 , 0x10 , 0x10 , 0x10 , + 0x10 , 0x20 , 0x20 , 0x20 , 0x20 , 0x20 , 0x20 , 0x30 , + 0x30 , 0x30 , 0x30 , 0x30 , 0x30 , 0x30 , 0x40 , 0x40 , + 0x40 , 0x40 , 0x40 , 0x40 , 0x40 , 0x50 , 0x50 , 0x50 , + 0x50 , 0x50 , 0x50 , 0x50 , 0x50 , 0x60 , 0x60 , 0x60 , + 0x60 , 0x60 , 0x60 , 0x60 , 0x60 , 0x60 , 0x60 , 0x60 , + 0x60 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , + 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , + 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , + 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , + 0x60 , 0x60 , 0x60 , 0x60 , 0x60 , 0x60 , 0x60 , 0x60 , + 0x60 , 0x60 , 0x60 , 0x60 , 0x50 , 0x50 , 0x50 , 0x50 , + 0x50 , 0x50 , 0x50 , 0x50 , 0x40 , 0x40 , 0x40 , 0x40 , + 0x40 , 0x40 , 0x40 , 0x30 , 0x30 , 0x30 , 0x30 , 0x30 , + 0x30 , 0x30 , 0x20 , 0x20 , 0x20 , 0x20 , 0x20 , 0x20 , + 0x10 , 0x10 , 0x10 , 0x10 , 0x10 , 0x10 , 0x00 , 0x00 , + 0x00 , 0x00 , 0x00 , 0xF0 , 0xF0 , 0xF0 , 0xF0 , 0xF0 , + 0xF0 , 0xE0 , 0xE0 , 0xE0 , 0xE0 , 0xE0 , 0xE0 , 0xD0 , + 0xD0 , 0xD0 , 0xD0 , 0xD0 , 0xD0 , 0xD0 , 0xC0 , 0xC0 , + 0xC0 , 0xC0 , 0xC0 , 0xC0 , 0xC0 , 0xB0 , 0xB0 , 0xB0 , + 0xB0 , 0xB0 , 0xB0 , 0xB0 , 0xB0 , 0xA0 , 0xA0 , 0xA0 , + 0xA0 , 0xA0 , 0xA0 , 0xA0 , 0xA0 , 0xA0 , 0xA0 , 0xA0 , + 0xA0 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , + 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , + 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , + 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , + 0xA0 , 0xA0 , 0xA0 , 0xA0 , 0xA0 , 0xA0 , 0xA0 , 0xA0 , + 0xA0 , 0xA0 , 0xA0 , 0xA0 , 0xB0 , 0xB0 , 0xB0 , 0xB0 , + 0xB0 , 0xB0 , 0xB0 , 0xB0 , 0xC0 , 0xC0 , 0xC0 , 0xC0 , + 0xC0 , 0xC0 , 0xC0 , 0xD0 , 0xD0 , 0xD0 , 0xD0 , 0xD0 , + 0xD0 , 0xD0 , 0xE0 , 0xE0 , 0xE0 , 0xE0 , 0xE0 , 0xE0 , + 0xF0 , 0xF0 , 0xF0 , 0xF0 , 0xF0 , 0xF0 , 0x00 , 0x00 }; //tab42496 -const unsigned char rectangle[] = +unsigned char rectangle[] = { - 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , - 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , - 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , - 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , - 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , - 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , - 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , - 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , - 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , - 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , - 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , - 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , - 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , - 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , - 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , - 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , - 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , - 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , - 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , - 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , - 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , - 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , - 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , - 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , - 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , - 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , - 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , - 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , - 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , - 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , - 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , - 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 + 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , + 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , + 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , + 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , + 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , + 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , + 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , + 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , + 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , + 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , + 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , + 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , + 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , + 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , + 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , + 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , 0x90 , + 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , + 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , + 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , + 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , + 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , + 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , + 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , + 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , + 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , + 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , + 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , + 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , + 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , + 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , + 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , + 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 , 0x70 }; +//tab42752 +unsigned char multtable[] = +{ + 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , + 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , + 0x00 , 0x00 , 1 , 1 , 2 , 2 , 3 , 3 , + 4 , 4 , 5 , 5 , 6 , 6 , 7 , 7 , + 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , + 8 , 9 ,0xA ,0xB ,0xC ,0xD ,0xE ,0xF , + 0x00 , 1 , 3 , 4 , 6 , 7 , 9 ,0xA , + 0xC ,0xD ,0xF , 0x10 , 0x12 , 0x13 , 0x15 , 0x16 , + 0x00 , 2 , 4 , 6 , 8 ,0xA ,0xC ,0xE , + 0x10 , 0x12 , 0x14 , 0x16 , 0x18 , 0x1A , 0x1C , 0x1E , + 0x00 , 2 , 5 , 7 ,0xA ,0xC ,0xF , 0x11 , + 0x14 , 0x16 , 0x19 , 0x1B , 0x1E , 0x20 , 0x23 , 0x25 , + 0x00 , 3 , 6 , 9 ,0xC ,0xF , 0x12 , 0x15 , + 0x18 , 0x1B , 0x1E , 0x21 , 0x24 , 0x27 , 0x2A , 0x2D , + 0x00 , 0x03 , 0x07 , 0x0A , 0x0E , 0x11 , 0x15 , 0x18 , + 0x1C , 0x1F , 0x23 , 0x26 , 0x2A , 0x2D , 0x31 , 0x34 , + 0x00 , 0xFC , 0xF8 , 0xF4 , 0xF0 , 0xEC , 0xE8 , 0xE4 , + 0xE0 , 0xDC , 0xD8 , 0xD4 , 0xD0 , 0xCC , 0xC8 , 0xC4 , + 0x00 , 0xFC , 0xF9 , 0xF5 , 0xF2 , 0xEE , 0xEB , 0xE7 , + 0xE4 , 0xE0 , 0xDD , 0xD9 , 0xD6 , 0xD2 , 0xCF , 0xCB , + 0x00 , 0xFD , 0xFA , 0xF7 , 0xF4 , 0xF1 , 0xEE , 0xEB , + 0xE8 , 0xE5 , 0xE2 , 0xDF , 0xDC , 0xD9 , 0xD6 , 0xD3 , + 0x00 , 0xFD , 0xFB , 0xF8 , 0xF6 , 0xF3 , 0xF1 , 0xEE , + 0xEC , 0xE9 , 0xE7 , 0xE4 , 0xE2 , 0xDF , 0xDD , 0xDA , + 0x00 , 0xFE , 0xFC , 0xFA , 0xF8 , 0xF6 , 0xF4 , 0xF2 , + 0xF0 , 0xEE , 0xEC , 0xEA , 0xE8 , 0xE6 , 0xE4 , 0xE2 , + 0x00 , 0xFE , 0xFD , 0xFB , 0xFA , 0xF8 , 0xF7 , 0xF5 , + 0xF4 , 0xF2 , 0xF1 , 0xEF , 0xEE , 0xEC , 0xEB , 0xE9 , + 0x00 , 0xFF , 0xFE , 0xFD , 0xFC , 0xFB , 0xFA , 0xF9 , + 0xF8 , 0xF7 , 0xF6 , 0xF5 , 0xF4 , 0xF3 , 0xF2 , 0xF1 , + 0x00 , 0xFF , 0xFF , 0xFE , 0xFE , 0xFD , 0xFD , 0xFC , + 0xFC , 0xFB , 0xFB , 0xFA , 0xFA , 0xF9 , 0xF9 , 0xF8 +}; + //random data ? -const unsigned char sampleTable[0x500] = +unsigned char sampleTable[0x500] = { - //00 + //00 - 0x38 , 0x84 , 0x6B , 0x19 , 0xC6 , 0x63 , 0x18 , 0x86 - , 0x73 , 0x98 , 0xC6 , 0xB1 , 0x1C , 0xCA , 0x31 , 0x8C - , 0xC7 , 0x31 , 0x88 , 0xC2 , 0x30 , 0x98 , 0x46 , 0x31 - , 0x18 , 0xC6 , 0x35 ,0xC , 0xCA , 0x31 ,0xC , 0xC6 - //20 - , 0x21 , 0x10 , 0x24 , 0x69 , 0x12 , 0xC2 , 0x31 , 0x14 - , 0xC4 , 0x71 , 8 , 0x4A , 0x22 , 0x49 , 0xAB , 0x6A - , 0xA8 , 0xAC , 0x49 , 0x51 , 0x32 , 0xD5 , 0x52 , 0x88 - , 0x93 , 0x6C , 0x94 , 0x22 , 0x15 , 0x54 , 0xD2 , 0x25 - //40 - , 0x96 , 0xD4 , 0x50 , 0xA5 , 0x46 , 0x21 , 8 , 0x85 - , 0x6B , 0x18 , 0xC4 , 0x63 , 0x10 , 0xCE , 0x6B , 0x18 - , 0x8C , 0x71 , 0x19 , 0x8C , 0x63 , 0x35 ,0xC , 0xC6 - , 0x33 , 0x99 , 0xCC , 0x6C , 0xB5 , 0x4E , 0xA2 , 0x99 - //60 - , 0x46 , 0x21 , 0x28 , 0x82 , 0x95 , 0x2E , 0xE3 , 0x30 - , 0x9C , 0xC5 , 0x30 , 0x9C , 0xA2 , 0xB1 , 0x9C , 0x67 - , 0x31 , 0x88 , 0x66 , 0x59 , 0x2C , 0x53 , 0x18 , 0x84 - , 0x67 , 0x50 , 0xCA , 0xE3 ,0xA , 0xAC , 0xAB , 0x30 - //80 - , 0xAC , 0x62 , 0x30 , 0x8C , 0x63 , 0x10 , 0x94 , 0x62 - , 0xB1 , 0x8C , 0x82 , 0x28 , 0x96 , 0x33 , 0x98 , 0xD6 - , 0xB5 , 0x4C , 0x62 , 0x29 , 0xA5 , 0x4A , 0xB5 , 0x9C - , 0xC6 , 0x31 , 0x14 , 0xD6 , 0x38 , 0x9C , 0x4B , 0xB4 - //A0 - , 0x86 , 0x65 , 0x18 , 0xAE , 0x67 , 0x1C , 0xA6 , 0x63 - , 0x19 , 0x96 , 0x23 , 0x19 , 0x84 , 0x13 , 8 , 0xA6 - , 0x52 , 0xAC , 0xCA , 0x22 , 0x89 , 0x6E , 0xAB , 0x19 - , 0x8C , 0x62 , 0x34 , 0xC4 , 0x62 , 0x19 , 0x86 , 0x63 - //C0 - , 0x18 , 0xC4 , 0x23 , 0x58 , 0xD6 , 0xA3 , 0x50 , 0x42 - , 0x54 , 0x4A , 0xAD , 0x4A , 0x25 , 0x11 , 0x6B , 0x64 - , 0x89 , 0x4A , 0x63 , 0x39 , 0x8A , 0x23 , 0x31 , 0x2A - , 0xEA , 0xA2 , 0xA9 , 0x44 , 0xC5 , 0x12 , 0xCD , 0x42 - //E0 - , 0x34 , 0x8C , 0x62 , 0x18 , 0x8C , 0x63 , 0x11 , 0x48 - , 0x66 , 0x31 , 0x9D , 0x44 , 0x33 , 0x1D , 0x46 , 0x31 - , 0x9C , 0xC6 , 0xB1 ,0xC , 0xCD , 0x32 , 0x88 , 0xC4 - , 0x73 , 0x18 , 0x86 , 0x73 , 8 , 0xD6 , 0x63 , 0x58 - //100 - , 7 , 0x81 , 0xE0 , 0xF0 , 0x3C , 7 , 0x87 , 0x90 - , 0x3C , 0x7C ,0xF , 0xC7 , 0xC0 , 0xC0 , 0xF0 , 0x7C - , 0x1E , 7 , 0x80 , 0x80 , 0 , 0x1C , 0x78 , 0x70 - , 0xF1 , 0xC7 , 0x1F , 0xC0 ,0xC , 0xFE , 0x1C , 0x1F - //120 - , 0x1F ,0xE ,0xA , 0x7A , 0xC0 , 0x71 , 0xF2 , 0x83 - , 0x8F , 3 ,0xF ,0xF ,0xC , 0 , 0x79 , 0xF8 - , 0x61 , 0xE0 , 0x43 ,0xF , 0x83 , 0xE7 , 0x18 , 0xF9 - , 0xC1 , 0x13 , 0xDA , 0xE9 , 0x63 , 0x8F ,0xF , 0x83 - //140 - , 0x83 , 0x87 , 0xC3 , 0x1F , 0x3C , 0x70 , 0xF0 , 0xE1 - , 0xE1 , 0xE3 , 0x87 , 0xB8 , 0x71 ,0xE , 0x20 , 0xE3 - , 0x8D , 0x48 , 0x78 , 0x1C , 0x93 , 0x87 , 0x30 , 0xE1 - , 0xC1 , 0xC1 , 0xE4 , 0x78 , 0x21 , 0x83 , 0x83 , 0xC3 - //160 - , 0x87 , 6 , 0x39 , 0xE5 , 0xC3 , 0x87 , 7 ,0xE - , 0x1C , 0x1C , 0x70 , 0xF4 , 0x71 , 0x9C , 0x60 , 0x36 - , 0x32 , 0xC3 , 0x1E , 0x3C , 0xF3 , 0x8F ,0xE , 0x3C - , 0x70 , 0xE3 , 0xC7 , 0x8F ,0xF ,0xF ,0xE , 0x3C - //180 - , 0x78 , 0xF0 , 0xE3 , 0x87 , 6 , 0xF0 , 0xE3 , 7 - , 0xC1 , 0x99 , 0x87 ,0xF , 0x18 , 0x78 , 0x70 , 0x70 - , 0xFC , 0xF3 , 0x10 , 0xB1 , 0x8C , 0x8C , 0x31 , 0x7C - , 0x70 , 0xE1 , 0x86 , 0x3C , 0x64 , 0x6C , 0xB0 , 0xE1 - //1A0 - , 0xE3 ,0xF , 0x23 , 0x8F ,0xF , 0x1E , 0x3E , 0x38 - , 0x3C , 0x38 , 0x7B , 0x8F , 7 ,0xE , 0x3C , 0xF4 - , 0x17 , 0x1E , 0x3C , 0x78 , 0xF2 , 0x9E , 0x72 , 0x49 - , 0xE3 , 0x25 , 0x36 , 0x38 , 0x58 , 0x39 , 0xE2 , 0xDE - //1C0 - , 0x3C , 0x78 , 0x78 , 0xE1 , 0xC7 , 0x61 , 0xE1 , 0xE1 - , 0xB0 , 0xF0 , 0xF0 , 0xC3 , 0xC7 ,0xE , 0x38 , 0xC0 - , 0xF0 , 0xCE , 0x73 , 0x73 , 0x18 , 0x34 , 0xB0 , 0xE1 - , 0xC7 , 0x8E , 0x1C , 0x3C , 0xF8 , 0x38 , 0xF0 , 0xE1 - //1E0 - , 0xC1 , 0x8B , 0x86 , 0x8F , 0x1C , 0x78 , 0x70 , 0xF0 - , 0x78 , 0xAC , 0xB1 , 0x8F , 0x39 , 0x31 , 0xDB , 0x38 - , 0x61 , 0xC3 ,0xE ,0xE , 0x38 , 0x78 , 0x73 , 0x17 - , 0x1E , 0x39 , 0x1E , 0x38 , 0x64 , 0xE1 , 0xF1 , 0xC1 - //200 - , 0x4E ,0xF , 0x40 , 0xA2 , 2 , 0xC5 , 0x8F , 0x81 - , 0xA1 , 0xFC , 0x12 , 8 , 0x64 , 0xE0 , 0x3C , 0x22 - , 0xE0 , 0x45 , 7 , 0x8E ,0xC , 0x32 , 0x90 , 0xF0 - , 0x1F , 0x20 , 0x49 , 0xE0 , 0xF8 ,0xC , 0x60 , 0xF0 - //220 - , 0x17 , 0x1A , 0x41 , 0xAA , 0xA4 , 0xD0 , 0x8D , 0x12 - , 0x82 , 0x1E , 0x1E , 3 , 0xF8 , 0x3E , 3 ,0xC - , 0x73 , 0x80 , 0x70 , 0x44 , 0x26 , 3 , 0x24 , 0xE1 - , 0x3E , 4 , 0x4E , 4 , 0x1C , 0xC1 , 9 , 0xCC - //240 - , 0x9E , 0x90 , 0x21 , 7 , 0x90 , 0x43 , 0x64 , 0xC0 - , 0xF , 0xC6 , 0x90 , 0x9C , 0xC1 , 0x5B , 3 , 0xE2 - , 0x1D , 0x81 , 0xE0 , 0x5E , 0x1D , 3 , 0x84 , 0xB8 - , 0x2C ,0xF , 0x80 , 0xB1 , 0x83 , 0xE0 , 0x30 , 0x41 - //260 - , 0x1E , 0x43 , 0x89 , 0x83 , 0x50 , 0xFC , 0x24 , 0x2E - , 0x13 , 0x83 , 0xF1 , 0x7C , 0x4C , 0x2C , 0xC9 ,0xD - , 0x83 , 0xB0 , 0xB5 , 0x82 , 0xE4 , 0xE8 , 6 , 0x9C - , 7 , 0xA0 , 0x99 , 0x1D , 7 , 0x3E , 0x82 , 0x8F - //280 - , 0x70 , 0x30 , 0x74 , 0x40 , 0xCA , 0x10 , 0xE4 , 0xE8 - , 0xF , 0x92 , 0x14 , 0x3F , 6 , 0xF8 , 0x84 , 0x88 - , 0x43 , 0x81 ,0xA , 0x34 , 0x39 , 0x41 , 0xC6 , 0xE3 - , 0x1C , 0x47 , 3 , 0xB0 , 0xB8 , 0x13 ,0xA , 0xC2 - //2A0 - , 0x64 , 0xF8 , 0x18 , 0xF9 , 0x60 , 0xB3 , 0xC0 , 0x65 - , 0x20 , 0x60 , 0xA6 , 0x8C , 0xC3 , 0x81 , 0x20 , 0x30 - , 0x26 , 0x1E , 0x1C , 0x38 , 0xD3 , 1 , 0xB0 , 0x26 - , 0x40 , 0xF4 ,0xB , 0xC3 , 0x42 , 0x1F , 0x85 , 0x32 - //2C0 - , 0x26 , 0x60 , 0x40 , 0xC9 , 0xCB , 1 , 0xEC , 0x11 - , 0x28 , 0x40 , 0xFA , 4 , 0x34 , 0xE0 , 0x70 , 0x4C - , 0x8C , 0x1D , 7 , 0x69 , 3 , 0x16 , 0xC8 , 4 - , 0x23 , 0xE8 , 0xC6 , 0x9A ,0xB , 0x1A , 3 , 0xE0 - //2E0 - , 0x76 , 6 , 5 , 0xCF , 0x1E , 0xBC , 0x58 , 0x31 - , 0x71 , 0x66 , 0 , 0xF8 , 0x3F , 4 , 0xFC ,0xC - , 0x74 , 0x27 , 0x8A , 0x80 , 0x71 , 0xC2 , 0x3A , 0x26 - , 6 , 0xC0 , 0x1F , 5 ,0xF , 0x98 , 0x40 , 0xAE - //300 - , 1 , 0x7F , 0xC0 , 7 , 0xFF , 0 ,0xE , 0xFE - , 0 , 3 , 0xDF , 0x80 , 3 , 0xEF , 0x80 , 0x1B - , 0xF1 , 0xC2 , 0 , 0xE7 , 0xE0 , 0x18 , 0xFC , 0xE0 - , 0x21 , 0xFC , 0x80 , 0x3C , 0xFC , 0x40 ,0xE , 0x7E - //320 - , 0 , 0x3F , 0x3E , 0 ,0xF , 0xFE , 0 , 0x1F - , 0xFF , 0 , 0x3E , 0xF0 , 7 , 0xFC , 0 , 0x7E - , 0x10 , 0x3F , 0xFF , 0 , 0x3F , 0x38 ,0xE , 0x7C - , 1 , 0x87 ,0xC , 0xFC , 0xC7 , 0 , 0x3E , 4 - //340 - , 0xF , 0x3E , 0x1F ,0xF ,0xF , 0x1F ,0xF , 2 - , 0x83 , 0x87 , 0xCF , 3 , 0x87 ,0xF , 0x3F , 0xC0 - , 7 , 0x9E , 0x60 , 0x3F , 0xC0 , 3 , 0xFE , 0 - , 0x3F , 0xE0 , 0x77 , 0xE1 , 0xC0 , 0xFE , 0xE0 , 0xC3 - //360 - , 0xE0 , 1 , 0xDF , 0xF8 , 3 , 7 , 0 , 0x7E - , 0x70 , 0 , 0x7C , 0x38 , 0x18 , 0xFE ,0xC , 0x1E - , 0x78 , 0x1C , 0x7C , 0x3E ,0xE , 0x1F , 0x1E , 0x1E - , 0x3E , 0 , 0x7F , 0x83 , 7 , 0xDB , 0x87 , 0x83 - //380 - , 7 , 0xC7 , 7 , 0x10 , 0x71 , 0xFF , 0 , 0x3F - , 0xE2 , 1 , 0xE0 , 0xC1 , 0xC3 , 0xE1 , 0 , 0x7F - , 0xC0 , 5 , 0xF0 , 0x20 , 0xF8 , 0xF0 , 0x70 , 0xFE - , 0x78 , 0x79 , 0xF8 , 2 , 0x3F ,0xC , 0x8F , 3 - //3a0 - , 0xF , 0x9F , 0xE0 , 0xC1 , 0xC7 , 0x87 , 3 , 0xC3 - , 0xC3 , 0xB0 , 0xE1 , 0xE1 , 0xC1 , 0xE3 , 0xE0 , 0x71 - , 0xF0 , 0 , 0xFC , 0x70 , 0x7C ,0xC , 0x3E , 0x38 - , 0xE , 0x1C , 0x70 , 0xC3 , 0xC7 , 3 , 0x81 , 0xC1 - //3c0 - , 0xC7 , 0xE7 , 0 ,0xF , 0xC7 , 0x87 , 0x19 , 9 - , 0xEF , 0xC4 , 0x33 , 0xE0 , 0xC1 , 0xFC , 0xF8 , 0x70 - , 0xF0 , 0x78 , 0xF8 , 0xF0 , 0x61 , 0xC7 , 0 , 0x1F - , 0xF8 , 1 , 0x7C , 0xF8 , 0xF0 , 0x78 , 0x70 , 0x3C - //3e0 - , 0x7C , 0xCE ,0xE , 0x21 , 0x83 , 0xCF , 8 , 7 - , 0x8F , 8 , 0xC1 , 0x87 , 0x8F , 0x80 , 0xC7 , 0xE3 - , 0 , 7 , 0xF8 , 0xE0 , 0xEF , 0 , 0x39 , 0xF7 - , 0x80 ,0xE , 0xF8 , 0xE1 , 0xE3 , 0xF8 , 0x21 , 0x9F - //400 - , 0xC0 , 0xFF , 3 , 0xF8 , 7 , 0xC0 , 0x1F , 0xF8 - , 0xC4 , 4 , 0xFC , 0xC4 , 0xC1 , 0xBC , 0x87 , 0xF0 - , 0xF , 0xC0 , 0x7F , 5 , 0xE0 , 0x25 , 0xEC , 0xC0 - , 0x3E , 0x84 , 0x47 , 0xF0 , 0x8E , 3 , 0xF8 , 3 - //420 - , 0xFB , 0xC0 , 0x19 , 0xF8 , 7 , 0x9C ,0xC , 0x17 - , 0xF8 , 7 , 0xE0 , 0x1F , 0xA1 , 0xFC ,0xF , 0xFC - , 1 , 0xF0 , 0x3F , 0 , 0xFE , 3 , 0xF0 , 0x1F - , 0 , 0xFD , 0 , 0xFF , 0x88 ,0xD , 0xF9 , 1 - //440 - , 0xFF , 0 , 0x70 , 7 , 0xC0 , 0x3E , 0x42 , 0xF3 - , 0xD , 0xC4 , 0x7F , 0x80 , 0xFC , 7 , 0xF0 , 0x5E - , 0xC0 , 0x3F , 0 , 0x78 , 0x3F , 0x81 , 0xFF , 1 - , 0xF8 , 1 , 0xC3 , 0xE8 ,0xC , 0xE4 , 0x64 , 0x8F - ////460 - , 0xE4 ,0xF , 0xF0 , 7 , 0xF0 , 0xC2 , 0x1F , 0 - , 0x7F , 0xC0 , 0x6F , 0x80 , 0x7E , 3 , 0xF8 , 7 - , 0xF0 , 0x3F , 0xC0 , 0x78 ,0xF , 0x82 , 7 , 0xFE - , 0x22 , 0x77 , 0x70 , 2 , 0x76 , 3 , 0xFE , 0 - //480 - , 0xFE , 0x67 , 0 , 0x7C , 0xC7 , 0xF1 , 0x8E , 0xC6 - , 0x3B , 0xE0 , 0x3F , 0x84 , 0xF3 , 0x19 , 0xD8 , 3 - , 0x99 , 0xFC , 9 , 0xB8 ,0xF , 0xF8 , 0 , 0x9D - , 0x24 , 0x61 , 0xF9 ,0xD , 0 , 0xFD , 3 , 0xF0 - //4a0 - , 0x1F , 0x90 , 0x3F , 1 , 0xF8 , 0x1F , 0xD0 ,0xF - , 0xF8 , 0x37 , 1 , 0xF8 , 7 , 0xF0 ,0xF , 0xC0 - , 0x3F , 0 , 0xFE , 3 , 0xF8 ,0xF , 0xC0 , 0x3F - , 0 , 0xFA , 3 , 0xF0 ,0xF , 0x80 , 0xFF , 1 - //4c0 - , 0xB8 , 7 , 0xF0 , 1 , 0xFC , 1 , 0xBC , 0x80 - , 0x13 , 0x1E , 0 , 0x7F , 0xE1 , 0x40 , 0x7F , 0xA0 - , 0x7F , 0xB0 , 0 , 0x3F , 0xC0 , 0x1F , 0xC0 , 0x38 - , 0xF , 0xF0 , 0x1F , 0x80 , 0xFF , 1 , 0xFC , 3 - //4e0 - , 0xF1 , 0x7E , 1 , 0xFE , 1 , 0xF0 , 0xFF , 0 - , 0x7F , 0xC0 , 0x1D , 7 , 0xF0 ,0xF , 0xC0 , 0x7E - , 6 , 0xE0 , 7 , 0xE0 ,0xF , 0xF8 , 6 , 0xC1 - , 0xFE , 1 , 0xFC , 3 , 0xE0 ,0xF , 0 , 0xFC + 0x38 , 0x84 , 0x6B , 0x19 , 0xC6 , 0x63 , 0x18 , 0x86 + , 0x73 , 0x98 , 0xC6 , 0xB1 , 0x1C , 0xCA , 0x31 , 0x8C + , 0xC7 , 0x31 , 0x88 , 0xC2 , 0x30 , 0x98 , 0x46 , 0x31 + , 0x18 , 0xC6 , 0x35 ,0xC , 0xCA , 0x31 ,0xC , 0xC6 + //20 + , 0x21 , 0x10 , 0x24 , 0x69 , 0x12 , 0xC2 , 0x31 , 0x14 + , 0xC4 , 0x71 , 8 , 0x4A , 0x22 , 0x49 , 0xAB , 0x6A + , 0xA8 , 0xAC , 0x49 , 0x51 , 0x32 , 0xD5 , 0x52 , 0x88 + , 0x93 , 0x6C , 0x94 , 0x22 , 0x15 , 0x54 , 0xD2 , 0x25 + //40 + , 0x96 , 0xD4 , 0x50 , 0xA5 , 0x46 , 0x21 , 8 , 0x85 + , 0x6B , 0x18 , 0xC4 , 0x63 , 0x10 , 0xCE , 0x6B , 0x18 + , 0x8C , 0x71 , 0x19 , 0x8C , 0x63 , 0x35 ,0xC , 0xC6 + , 0x33 , 0x99 , 0xCC , 0x6C , 0xB5 , 0x4E , 0xA2 , 0x99 + //60 + , 0x46 , 0x21 , 0x28 , 0x82 , 0x95 , 0x2E , 0xE3 , 0x30 + , 0x9C , 0xC5 , 0x30 , 0x9C , 0xA2 , 0xB1 , 0x9C , 0x67 + , 0x31 , 0x88 , 0x66 , 0x59 , 0x2C , 0x53 , 0x18 , 0x84 + , 0x67 , 0x50 , 0xCA , 0xE3 ,0xA , 0xAC , 0xAB , 0x30 + //80 + , 0xAC , 0x62 , 0x30 , 0x8C , 0x63 , 0x10 , 0x94 , 0x62 + , 0xB1 , 0x8C , 0x82 , 0x28 , 0x96 , 0x33 , 0x98 , 0xD6 + , 0xB5 , 0x4C , 0x62 , 0x29 , 0xA5 , 0x4A , 0xB5 , 0x9C + , 0xC6 , 0x31 , 0x14 , 0xD6 , 0x38 , 0x9C , 0x4B , 0xB4 + //A0 + , 0x86 , 0x65 , 0x18 , 0xAE , 0x67 , 0x1C , 0xA6 , 0x63 + , 0x19 , 0x96 , 0x23 , 0x19 , 0x84 , 0x13 , 8 , 0xA6 + , 0x52 , 0xAC , 0xCA , 0x22 , 0x89 , 0x6E , 0xAB , 0x19 + , 0x8C , 0x62 , 0x34 , 0xC4 , 0x62 , 0x19 , 0x86 , 0x63 + //C0 + , 0x18 , 0xC4 , 0x23 , 0x58 , 0xD6 , 0xA3 , 0x50 , 0x42 + , 0x54 , 0x4A , 0xAD , 0x4A , 0x25 , 0x11 , 0x6B , 0x64 + , 0x89 , 0x4A , 0x63 , 0x39 , 0x8A , 0x23 , 0x31 , 0x2A + , 0xEA , 0xA2 , 0xA9 , 0x44 , 0xC5 , 0x12 , 0xCD , 0x42 + //E0 + , 0x34 , 0x8C , 0x62 , 0x18 , 0x8C , 0x63 , 0x11 , 0x48 + , 0x66 , 0x31 , 0x9D , 0x44 , 0x33 , 0x1D , 0x46 , 0x31 + , 0x9C , 0xC6 , 0xB1 ,0xC , 0xCD , 0x32 , 0x88 , 0xC4 + , 0x73 , 0x18 , 0x86 , 0x73 , 8 , 0xD6 , 0x63 , 0x58 + //100 + , 7 , 0x81 , 0xE0 , 0xF0 , 0x3C , 7 , 0x87 , 0x90 + , 0x3C , 0x7C ,0xF , 0xC7 , 0xC0 , 0xC0 , 0xF0 , 0x7C + , 0x1E , 7 , 0x80 , 0x80 , 0 , 0x1C , 0x78 , 0x70 + , 0xF1 , 0xC7 , 0x1F , 0xC0 ,0xC , 0xFE , 0x1C , 0x1F + //120 + , 0x1F ,0xE ,0xA , 0x7A , 0xC0 , 0x71 , 0xF2 , 0x83 + , 0x8F , 3 ,0xF ,0xF ,0xC , 0 , 0x79 , 0xF8 + , 0x61 , 0xE0 , 0x43 ,0xF , 0x83 , 0xE7 , 0x18 , 0xF9 + , 0xC1 , 0x13 , 0xDA , 0xE9 , 0x63 , 0x8F ,0xF , 0x83 + //140 + , 0x83 , 0x87 , 0xC3 , 0x1F , 0x3C , 0x70 , 0xF0 , 0xE1 + , 0xE1 , 0xE3 , 0x87 , 0xB8 , 0x71 ,0xE , 0x20 , 0xE3 + , 0x8D , 0x48 , 0x78 , 0x1C , 0x93 , 0x87 , 0x30 , 0xE1 + , 0xC1 , 0xC1 , 0xE4 , 0x78 , 0x21 , 0x83 , 0x83 , 0xC3 + //160 + , 0x87 , 6 , 0x39 , 0xE5 , 0xC3 , 0x87 , 7 ,0xE + , 0x1C , 0x1C , 0x70 , 0xF4 , 0x71 , 0x9C , 0x60 , 0x36 + , 0x32 , 0xC3 , 0x1E , 0x3C , 0xF3 , 0x8F ,0xE , 0x3C + , 0x70 , 0xE3 , 0xC7 , 0x8F ,0xF ,0xF ,0xE , 0x3C + //180 + , 0x78 , 0xF0 , 0xE3 , 0x87 , 6 , 0xF0 , 0xE3 , 7 + , 0xC1 , 0x99 , 0x87 ,0xF , 0x18 , 0x78 , 0x70 , 0x70 + , 0xFC , 0xF3 , 0x10 , 0xB1 , 0x8C , 0x8C , 0x31 , 0x7C + , 0x70 , 0xE1 , 0x86 , 0x3C , 0x64 , 0x6C , 0xB0 , 0xE1 + //1A0 + , 0xE3 ,0xF , 0x23 , 0x8F ,0xF , 0x1E , 0x3E , 0x38 + , 0x3C , 0x38 , 0x7B , 0x8F , 7 ,0xE , 0x3C , 0xF4 + , 0x17 , 0x1E , 0x3C , 0x78 , 0xF2 , 0x9E , 0x72 , 0x49 + , 0xE3 , 0x25 , 0x36 , 0x38 , 0x58 , 0x39 , 0xE2 , 0xDE + //1C0 + , 0x3C , 0x78 , 0x78 , 0xE1 , 0xC7 , 0x61 , 0xE1 , 0xE1 + , 0xB0 , 0xF0 , 0xF0 , 0xC3 , 0xC7 ,0xE , 0x38 , 0xC0 + , 0xF0 , 0xCE , 0x73 , 0x73 , 0x18 , 0x34 , 0xB0 , 0xE1 + , 0xC7 , 0x8E , 0x1C , 0x3C , 0xF8 , 0x38 , 0xF0 , 0xE1 + //1E0 + , 0xC1 , 0x8B , 0x86 , 0x8F , 0x1C , 0x78 , 0x70 , 0xF0 + , 0x78 , 0xAC , 0xB1 , 0x8F , 0x39 , 0x31 , 0xDB , 0x38 + , 0x61 , 0xC3 ,0xE ,0xE , 0x38 , 0x78 , 0x73 , 0x17 + , 0x1E , 0x39 , 0x1E , 0x38 , 0x64 , 0xE1 , 0xF1 , 0xC1 + //200 + , 0x4E ,0xF , 0x40 , 0xA2 , 2 , 0xC5 , 0x8F , 0x81 + , 0xA1 , 0xFC , 0x12 , 8 , 0x64 , 0xE0 , 0x3C , 0x22 + , 0xE0 , 0x45 , 7 , 0x8E ,0xC , 0x32 , 0x90 , 0xF0 + , 0x1F , 0x20 , 0x49 , 0xE0 , 0xF8 ,0xC , 0x60 , 0xF0 + //220 + , 0x17 , 0x1A , 0x41 , 0xAA , 0xA4 , 0xD0 , 0x8D , 0x12 + , 0x82 , 0x1E , 0x1E , 3 , 0xF8 , 0x3E , 3 ,0xC + , 0x73 , 0x80 , 0x70 , 0x44 , 0x26 , 3 , 0x24 , 0xE1 + , 0x3E , 4 , 0x4E , 4 , 0x1C , 0xC1 , 9 , 0xCC + //240 + , 0x9E , 0x90 , 0x21 , 7 , 0x90 , 0x43 , 0x64 , 0xC0 + , 0xF , 0xC6 , 0x90 , 0x9C , 0xC1 , 0x5B , 3 , 0xE2 + , 0x1D , 0x81 , 0xE0 , 0x5E , 0x1D , 3 , 0x84 , 0xB8 + , 0x2C ,0xF , 0x80 , 0xB1 , 0x83 , 0xE0 , 0x30 , 0x41 + //260 + , 0x1E , 0x43 , 0x89 , 0x83 , 0x50 , 0xFC , 0x24 , 0x2E + , 0x13 , 0x83 , 0xF1 , 0x7C , 0x4C , 0x2C , 0xC9 ,0xD + , 0x83 , 0xB0 , 0xB5 , 0x82 , 0xE4 , 0xE8 , 6 , 0x9C + , 7 , 0xA0 , 0x99 , 0x1D , 7 , 0x3E , 0x82 , 0x8F + //280 + , 0x70 , 0x30 , 0x74 , 0x40 , 0xCA , 0x10 , 0xE4 , 0xE8 + , 0xF , 0x92 , 0x14 , 0x3F , 6 , 0xF8 , 0x84 , 0x88 + , 0x43 , 0x81 ,0xA , 0x34 , 0x39 , 0x41 , 0xC6 , 0xE3 + , 0x1C , 0x47 , 3 , 0xB0 , 0xB8 , 0x13 ,0xA , 0xC2 + //2A0 + , 0x64 , 0xF8 , 0x18 , 0xF9 , 0x60 , 0xB3 , 0xC0 , 0x65 + , 0x20 , 0x60 , 0xA6 , 0x8C , 0xC3 , 0x81 , 0x20 , 0x30 + , 0x26 , 0x1E , 0x1C , 0x38 , 0xD3 , 1 , 0xB0 , 0x26 + , 0x40 , 0xF4 ,0xB , 0xC3 , 0x42 , 0x1F , 0x85 , 0x32 + //2C0 + , 0x26 , 0x60 , 0x40 , 0xC9 , 0xCB , 1 , 0xEC , 0x11 + , 0x28 , 0x40 , 0xFA , 4 , 0x34 , 0xE0 , 0x70 , 0x4C + , 0x8C , 0x1D , 7 , 0x69 , 3 , 0x16 , 0xC8 , 4 + , 0x23 , 0xE8 , 0xC6 , 0x9A ,0xB , 0x1A , 3 , 0xE0 + //2E0 + , 0x76 , 6 , 5 , 0xCF , 0x1E , 0xBC , 0x58 , 0x31 + , 0x71 , 0x66 , 0 , 0xF8 , 0x3F , 4 , 0xFC ,0xC + , 0x74 , 0x27 , 0x8A , 0x80 , 0x71 , 0xC2 , 0x3A , 0x26 + , 6 , 0xC0 , 0x1F , 5 ,0xF , 0x98 , 0x40 , 0xAE + //300 + , 1 , 0x7F , 0xC0 , 7 , 0xFF , 0 ,0xE , 0xFE + , 0 , 3 , 0xDF , 0x80 , 3 , 0xEF , 0x80 , 0x1B + , 0xF1 , 0xC2 , 0 , 0xE7 , 0xE0 , 0x18 , 0xFC , 0xE0 + , 0x21 , 0xFC , 0x80 , 0x3C , 0xFC , 0x40 ,0xE , 0x7E + //320 + , 0 , 0x3F , 0x3E , 0 ,0xF , 0xFE , 0 , 0x1F + , 0xFF , 0 , 0x3E , 0xF0 , 7 , 0xFC , 0 , 0x7E + , 0x10 , 0x3F , 0xFF , 0 , 0x3F , 0x38 ,0xE , 0x7C + , 1 , 0x87 ,0xC , 0xFC , 0xC7 , 0 , 0x3E , 4 + //340 + , 0xF , 0x3E , 0x1F ,0xF ,0xF , 0x1F ,0xF , 2 + , 0x83 , 0x87 , 0xCF , 3 , 0x87 ,0xF , 0x3F , 0xC0 + , 7 , 0x9E , 0x60 , 0x3F , 0xC0 , 3 , 0xFE , 0 + , 0x3F , 0xE0 , 0x77 , 0xE1 , 0xC0 , 0xFE , 0xE0 , 0xC3 + //360 + , 0xE0 , 1 , 0xDF , 0xF8 , 3 , 7 , 0 , 0x7E + , 0x70 , 0 , 0x7C , 0x38 , 0x18 , 0xFE ,0xC , 0x1E + , 0x78 , 0x1C , 0x7C , 0x3E ,0xE , 0x1F , 0x1E , 0x1E + , 0x3E , 0 , 0x7F , 0x83 , 7 , 0xDB , 0x87 , 0x83 + //380 + , 7 , 0xC7 , 7 , 0x10 , 0x71 , 0xFF , 0 , 0x3F + , 0xE2 , 1 , 0xE0 , 0xC1 , 0xC3 , 0xE1 , 0 , 0x7F + , 0xC0 , 5 , 0xF0 , 0x20 , 0xF8 , 0xF0 , 0x70 , 0xFE + , 0x78 , 0x79 , 0xF8 , 2 , 0x3F ,0xC , 0x8F , 3 + //3a0 + , 0xF , 0x9F , 0xE0 , 0xC1 , 0xC7 , 0x87 , 3 , 0xC3 + , 0xC3 , 0xB0 , 0xE1 , 0xE1 , 0xC1 , 0xE3 , 0xE0 , 0x71 + , 0xF0 , 0 , 0xFC , 0x70 , 0x7C ,0xC , 0x3E , 0x38 + , 0xE , 0x1C , 0x70 , 0xC3 , 0xC7 , 3 , 0x81 , 0xC1 + //3c0 + , 0xC7 , 0xE7 , 0 ,0xF , 0xC7 , 0x87 , 0x19 , 9 + , 0xEF , 0xC4 , 0x33 , 0xE0 , 0xC1 , 0xFC , 0xF8 , 0x70 + , 0xF0 , 0x78 , 0xF8 , 0xF0 , 0x61 , 0xC7 , 0 , 0x1F + , 0xF8 , 1 , 0x7C , 0xF8 , 0xF0 , 0x78 , 0x70 , 0x3C + //3e0 + , 0x7C , 0xCE ,0xE , 0x21 , 0x83 , 0xCF , 8 , 7 + , 0x8F , 8 , 0xC1 , 0x87 , 0x8F , 0x80 , 0xC7 , 0xE3 + , 0 , 7 , 0xF8 , 0xE0 , 0xEF , 0 , 0x39 , 0xF7 + , 0x80 ,0xE , 0xF8 , 0xE1 , 0xE3 , 0xF8 , 0x21 , 0x9F + //400 + , 0xC0 , 0xFF , 3 , 0xF8 , 7 , 0xC0 , 0x1F , 0xF8 + , 0xC4 , 4 , 0xFC , 0xC4 , 0xC1 , 0xBC , 0x87 , 0xF0 + , 0xF , 0xC0 , 0x7F , 5 , 0xE0 , 0x25 , 0xEC , 0xC0 + , 0x3E , 0x84 , 0x47 , 0xF0 , 0x8E , 3 , 0xF8 , 3 + //420 + , 0xFB , 0xC0 , 0x19 , 0xF8 , 7 , 0x9C ,0xC , 0x17 + , 0xF8 , 7 , 0xE0 , 0x1F , 0xA1 , 0xFC ,0xF , 0xFC + , 1 , 0xF0 , 0x3F , 0 , 0xFE , 3 , 0xF0 , 0x1F + , 0 , 0xFD , 0 , 0xFF , 0x88 ,0xD , 0xF9 , 1 + //440 + , 0xFF , 0 , 0x70 , 7 , 0xC0 , 0x3E , 0x42 , 0xF3 + , 0xD , 0xC4 , 0x7F , 0x80 , 0xFC , 7 , 0xF0 , 0x5E + , 0xC0 , 0x3F , 0 , 0x78 , 0x3F , 0x81 , 0xFF , 1 + , 0xF8 , 1 , 0xC3 , 0xE8 ,0xC , 0xE4 , 0x64 , 0x8F + ////460 + , 0xE4 ,0xF , 0xF0 , 7 , 0xF0 , 0xC2 , 0x1F , 0 + , 0x7F , 0xC0 , 0x6F , 0x80 , 0x7E , 3 , 0xF8 , 7 + , 0xF0 , 0x3F , 0xC0 , 0x78 ,0xF , 0x82 , 7 , 0xFE + , 0x22 , 0x77 , 0x70 , 2 , 0x76 , 3 , 0xFE , 0 + //480 + , 0xFE , 0x67 , 0 , 0x7C , 0xC7 , 0xF1 , 0x8E , 0xC6 + , 0x3B , 0xE0 , 0x3F , 0x84 , 0xF3 , 0x19 , 0xD8 , 3 + , 0x99 , 0xFC , 9 , 0xB8 ,0xF , 0xF8 , 0 , 0x9D + , 0x24 , 0x61 , 0xF9 ,0xD , 0 , 0xFD , 3 , 0xF0 + //4a0 + , 0x1F , 0x90 , 0x3F , 1 , 0xF8 , 0x1F , 0xD0 ,0xF + , 0xF8 , 0x37 , 1 , 0xF8 , 7 , 0xF0 ,0xF , 0xC0 + , 0x3F , 0 , 0xFE , 3 , 0xF8 ,0xF , 0xC0 , 0x3F + , 0 , 0xFA , 3 , 0xF0 ,0xF , 0x80 , 0xFF , 1 + //4c0 + , 0xB8 , 7 , 0xF0 , 1 , 0xFC , 1 , 0xBC , 0x80 + , 0x13 , 0x1E , 0 , 0x7F , 0xE1 , 0x40 , 0x7F , 0xA0 + , 0x7F , 0xB0 , 0 , 0x3F , 0xC0 , 0x1F , 0xC0 , 0x38 + , 0xF , 0xF0 , 0x1F , 0x80 , 0xFF , 1 , 0xFC , 3 + //4e0 + , 0xF1 , 0x7E , 1 , 0xFE , 1 , 0xF0 , 0xFF , 0 + , 0x7F , 0xC0 , 0x1D , 7 , 0xF0 ,0xF , 0xC0 , 0x7E + , 6 , 0xE0 , 7 , 0xE0 ,0xF , 0xF8 , 6 , 0xC1 + , 0xFE , 1 , 0xFC , 3 , 0xE0 ,0xF , 0 , 0xFC }; diff --git a/src/amiga/portaudio/portaudio.c b/src/amiga/portaudio/portaudio.c new file mode 100644 index 00000000..6bfe785b --- /dev/null +++ b/src/amiga/portaudio/portaudio.c @@ -0,0 +1,134 @@ +/*************************************************************************** + * Copyright (C) 2017 by Alexander Fritsch * + * email: selco@t-online.de * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write see: * + * . * + ***************************************************************************/ + +#include "portaudio_audev.h" +#include "portaudio_ahidev.h" +#include + + +///////////////////////////////////////////////////////////////////////////////////////// +// Functions are called via function pointers +// pointers point to audio.device or ahi.device functions + +// defaults to amiga audio.device +PaError (*Pa_StartStream_FctPtr)( PortAudioStream *stream ) = Pa_StartStream_audev; +PaError (*Pa_AbortStream_FctPtr)( PortAudioStream *stream ) = Pa_AbortStream_audev; +PaError (*Pa_StreamActive_FctPtr)( PortAudioStream *stream ) =Pa_StreamActive_audev; +PaError (*Pa_OpenDefaultStream_FctPtr)( PortAudioStream** stream, + int numInputChannels, + int numOutputChannels, + PaSampleFormat sampleFormat, + double sampleRate, + unsigned long framesPerBuffer, + unsigned long numberOfBuffers, + PortAudioCallback *callback, + void *userData ) = Pa_OpenDefaultStream_audev; +PaError (*Pa_CloseStream_FctPtr)( PortAudioStream *stream ) =Pa_CloseStream_audev; +PaError (*Pa_Initialize_FctPtr)( void ) =Pa_Initialize_audev; +PaError (*Pa_GetSampleSize_FctPtr)( PaSampleFormat format ) =Pa_GetSampleSize_audev; +void (*Abort_Pa_CloseStream_FctPtr) (void) =Abort_Pa_CloseStream_audev; + + +void set_paula_devide(void) +{ + Pa_StartStream_FctPtr = Pa_StartStream_audev; + Pa_AbortStream_FctPtr = Pa_AbortStream_audev; + Pa_StreamActive_FctPtr = Pa_StreamActive_audev; + Pa_OpenDefaultStream_FctPtr= Pa_OpenDefaultStream_audev; + Pa_CloseStream_FctPtr = Pa_CloseStream_audev; + Pa_Initialize_FctPtr = Pa_Initialize_audev; + Pa_GetSampleSize_FctPtr = Pa_GetSampleSize_audev; + Abort_Pa_CloseStream_FctPtr = Abort_Pa_CloseStream_audev; + + //printf("Setting portaudio to to audio.device\n"); +} + +void set_ahi_devide(unsigned int unit) +{ + Pa_StartStream_FctPtr = Pa_StartStream_ahidev; + Pa_AbortStream_FctPtr = Pa_AbortStream_ahidev; + Pa_StreamActive_FctPtr = Pa_StreamActive_ahidev; + Pa_OpenDefaultStream_FctPtr= Pa_OpenDefaultStream_ahidev; + Pa_CloseStream_FctPtr = Pa_CloseStream_ahidev; + Pa_Initialize_FctPtr = Pa_Initialize_ahidev; + Pa_GetSampleSize_FctPtr = Pa_GetSampleSize_ahidev; + Abort_Pa_CloseStream_FctPtr = Abort_Pa_CloseStream_ahidev; + g_AHI_Unit=unit; + //printf("Setting portaudio to to ahi.device, Unit %d\n",unit); +} + + +PaError Pa_StartStream( PortAudioStream *stream ) +{ + return (*Pa_StartStream_FctPtr)( stream); +} + + +PaError Pa_AbortStream( PortAudioStream *stream ) +{ + return (*Pa_AbortStream_FctPtr)( stream); +} + +PaError Pa_StreamActive( PortAudioStream *stream ) +{ + return (*Pa_StreamActive_FctPtr)( stream ); +} + +PaError Pa_OpenDefaultStream( PortAudioStream** stream, + int numInputChannels, + int numOutputChannels, + PaSampleFormat sampleFormat, + double sampleRate, + unsigned long framesPerBuffer, + unsigned long numberOfBuffers, + PortAudioCallback *callback, + void *userData ) +{ + return (*Pa_OpenDefaultStream_FctPtr)( stream, + numInputChannels, + numOutputChannels, + sampleFormat, + sampleRate, + framesPerBuffer, + numberOfBuffers, + callback, + userData ); + +} + +PaError Pa_CloseStream( PortAudioStream *stream ) +{ + return (*Pa_CloseStream_FctPtr)( stream ); +} + +PaError Pa_Initialize( void ) +{ + return (*Pa_Initialize_FctPtr)(); +} + +PaError Pa_GetSampleSize( PaSampleFormat format ) +{ + return (*Pa_GetSampleSize_FctPtr)( format ); +} + +void Abort_Pa_CloseStream (void) +{ + (*Abort_Pa_CloseStream_FctPtr)(); +} + diff --git a/src/amiga/portaudio/portaudio_ahidev.c b/src/amiga/portaudio/portaudio_ahidev.c new file mode 100644 index 00000000..cdf2cb7a --- /dev/null +++ b/src/amiga/portaudio/portaudio_ahidev.c @@ -0,0 +1,907 @@ +/*************************************************************************** + * Copyright (C) 2017 by Alexander Fritsch * + * email: selco@t-online.de * + ***************************************************************************/ + +/* Amiga ahi.device part */ + +#include "../portaudio18.h" +#include +#include + +/* AF, Gwd, 28.Nov 2017 */ + +#include +#include "subtask_support.h" + +#include + +#include +#include + +#include /* for CreatePort */ + +#include +#include + +#include +#include // sleep + +#include "portaudio_ahidev.h" + +#ifdef mc68060 +#define __CPU__ "mc68060" +#elif defined mc68040 +#define __CPU__ "mc68040" +#elif defined mc68030 +#define __CPU__ "mc68030" +#elif defined mc68020 +#define __CPU__ "mc68020" +#elif defined mc68000 +#define __CPU__ "mc68000" +#else +#define __CPU__ "???????" +#endif + +#ifdef __HAVE_68881__ +#define __FPU__ "mc68881" +#else +#define __FPU__ "" +#endif + +/*extern "C"*/ LONG KPrintF(STRPTR format, ...); +/* +extern unsigned int global_bufsize_factor; // AF Test einstellbare Audio Buffergroesse n mal 512 Bytes +extern unsigned int global_benchmark_flag; // AF Einschalten der Ausgabe der durchschnittlichen Zeit fuer die portaudio-Callbackfunktion +extern char *global_ProgramName; // AF argv[0] +*/ +/* +FILE *File_ahi=NULL; // testweise samples in File schreiben +*/ +unsigned int g_AHI_Unit=0; // can be changed via command line (speak.cpp) + +//UBYTE chans[] ={1,2,4,8}; /* get any of the four channels RKRM Audio-example */ +UBYTE chans_ahi[] ={3,5,10,12}; /* get a pair of stereo channels, RKRM Devices */ +//UBYTE chans[] ={1,8}; /* test, nur rechts */ +//UBYTE chans[] ={2,4}; /* test, nur links */ + +typedef struct +{ + int StreamActive; + unsigned int AF_StreamID; // just a number to see which stream is referred to + + struct SubTask *st; + struct SignalSemaphore sema; /* data item protection */ + + int numInputChannels; + int numOutputChannels; // 1 for mono, 2 for stereo + PaSampleFormat sampleFormat; + ULONG AhiSampleType; + double sampleRate; + unsigned long framesPerBuffer; // a frames is one complete sample from each channel + unsigned long numberOfBuffers; // suggestion for (double) bufering + PortAudioCallback *callback; + void *userData; + struct AHIRequest *AHIio; // audio I/O block + struct AHIRequest *AHIio2; // audio I/O block + struct AHIRequest *AIOptrStartStop;// for CMD_START and CMD_STOP + struct MsgPort *AHImp; + struct MsgPort *portStartStop; + ULONG device; // Audio device handle +// BYTE *ChipMemBuf1; // Amiga-Audiobuffer +// BYTE *ChipMemBuf2; // Amiga-Audiobuffer + SHORT *FastMemBuf1; // Espeak-AudioBuffer used in Callback + SHORT *FastMemBuf2; // Espeak-AudioBuffer used in Callback +// unsigned int LeftChannel; // left Audiochannel we got allocated in OpenDevice() or 0 +// unsigned int RightChannel; // right Audiochannel we got allocated in OpenDevice() or 0 + + +}PortAudioStreamStruct; + +//static UWORD Convert16SSamples(SHORT *Source16S, BYTE *Dest8S, ULONG SampleCount); /* reads 16Bit Signed Samples from Source and writes 8Bit Signed Samples to Dest. DestLen Samples will be read */ + +STATIC_FUNC ULONG getAHISampleType(PaSampleFormat format ); + + +void ConvertU8Samples(UBYTE *data, unsigned int SampleCount) // AHI does not support UINT8-Samples !??? +{ + unsigned long i; + for(i=0;itc_UserData = (APTR)((struct Process *)task)->pr_CIS; // the main task put a4 via NP_Input into pr_CIS + __restore_a4(); // get A4 from there. Now we can access static and global data via A4 ! + + // now fix CIN to zero or allocate something or ... + ((struct Process *)task)->pr_CIS = 0; + } + + + struct Task *me = FindTask(NULL); + struct SubTask *st; + struct SubTaskMsg *stm; + + //KPrintF("Begin EspeakAudioTask_AHI\n"); + + + /* + ** Wait for our startup message from the SpawnSubTask() function. + */ + + WaitPort(&((struct Process *)me)->pr_MsgPort); + stm = (struct SubTaskMsg *)GetMsg(&((struct Process *)me)->pr_MsgPort); + st = (struct SubTask *)stm->stm_Parameter; + + + + + { + // struct Data *data = (struct Data *)st->st_Data; + BOOL running = TRUE; + BOOL worktodo = FALSE; + + PortAudioStreamStruct *PortAudioStreamData=(PortAudioStreamStruct*)(st->st_Data); + //int Error=paInternalError; + + /* Make four Reply-Ports */ + PortAudioStreamData->AHImp=CreatePort(0,0); + if(PortAudioStreamData->AHImp) + { + + PortAudioStreamData->portStartStop=CreatePort(0,0); + if(PortAudioStreamData->portStartStop) + { + //KPrintF("if(PortAudioStreamData->portStartStop)\n"); + + /* Now Open AHI Device */ + // KPrintF("Attempting to open Audio.device\n"); + /* set up audio I/O block for channel */ + /* allocation and Open the audio.device */ + PortAudioStreamData->AHIio->ahir_Std.io_Message.mn_ReplyPort=PortAudioStreamData->AHImp; + PortAudioStreamData->AHIio->ahir_Std.io_Message.mn_Length=sizeof(struct AHIRequest); + PortAudioStreamData->AHIio->ahir_Version = 4; + + + // ((struct IORequest*)(PortAudioStreamData->AHIio))->io_Message.mn_ReplyPort=PortAudioStreamData->AHImp; + // PortAudioStreamData->AHIio=(struct AHIRequest *)CreateIORequest(PortAudioStreamData->AHImp,sizeof(struct AHIRequest)); + // PortAudioStreamData->AHIio->ahir_Version = 4; + + //KPrintF("Vor Open AHI-Device()\n"); + PortAudioStreamData->device=OpenDevice((CONST_STRPTR)AHINAME,g_AHI_Unit,(struct IORequest*)PortAudioStreamData->AHIio,0L); + //KPrintF("Nach Open AHI-Device()\n"); + + if(PortAudioStreamData->device==0) + { + /* + // PortAudioStreamData->AHIio->ahir_Std.io_Message.mn_Node.ln_Pri = pri; + // PortAudioStreamData->AHIio->ahir_Std.io_Data = ; + // PortAudioStreamData->AHIio->ahir_Std.io_Length = ; + PortAudioStreamData->AHIio->ahir_Std.io_Offset = 0; + PortAudioStreamData->AHIio->ahir_Frequency = (ULONG) PortAudioStreamData->sampleRate; + // PortAudioStreamData->AHIio->ahir_Type = TYPE; // AHIST_M16S + PortAudioStreamData->AHIio->ahir_Volume = 0x10000; // Full volume + PortAudioStreamData->AHIio->ahir_Position = 0x8000; // Centered + // PortAudioStreamData->AHIio->ahir_Link = ; + */ + // Make a copy of the request (for double buffer + *(PortAudioStreamData->AHIio2)=*(PortAudioStreamData->AHIio); + + PortAudioStreamData->AHIio->ahir_Std.io_Command=CMD_WRITE; + + + + /* Set Up Audio IO Blocks for Sample Playing */ + + + + // Data... + + if ((st->st_Port = CreateMsgPort())) + { + /* + ** Reply startup message, everything ok. + ** Note that if the initialization fails, the code falls + ** through and replies the startup message with a stm_Result + ** of 0 after a Forbid(). This tells SpawnSubTask() that the + ** sub task failed to run. + */ + + /* variables are declared here because they should be initialized to Zero */ + /* in the for loop they would become initialized at the beginning of every turn - which is wrong */ + //ULONG CallbackTime=0; /* For Callback benchmarking */ + //ULONG CallBackCount=0; + //ULONG CallBackMaxTime=0; + + ULONG BufferLength=PortAudioStreamData->framesPerBuffer * Pa_GetSampleSize_ahidev(PortAudioStreamData->sampleFormat); + + + + // struct IOAudio *Aptr=NULL; /* for double buffer switching */ + // struct MsgPort *port=NULL; /* for double buffer switching */ + // struct MsgPort *port_2=NULL; /* for double buffer switching for the second audio channel (we do 2-channel(MONO) playback)*/ + // BYTE *ChipMemBuf=NULL; /* Amiga-Audiobuffer for double buffer switching */ + // SHORT *FastMemBuf=NULL; /* Espeak-AudioBuffer used in Callback for double buffer switching */ + + struct AHIRequest *AHIio =PortAudioStreamData->AHIio; + struct AHIRequest *AHIio2=PortAudioStreamData->AHIio2; + struct AHIRequest *tmpReq=NULL; + struct AHIRequest *link = NULL; + WORD *tmpBuf=NULL; + WORD *p1=PortAudioStreamData->FastMemBuf1; + WORD *p2=PortAudioStreamData->FastMemBuf2; + + + stm->stm_Result = TRUE; + ReplyMsg((struct Message *)stm); + // Ok, all opened successfully + // KPrintF("Opened Audio.device successfully\n"); + + /* + ** after the sub task is up and running, we go into + ** a loop and process the messages from the main task. + */ + for (;;) + { + while ((stm = (struct SubTaskMsg *)GetMsg(st->st_Port))) + { + switch (stm->stm_Command) + { + case STC_SHUTDOWN: + /* + ** This is the shutdown message from KillSubTask(). + */ + // printf("Task STC_SHUTDOWN\n"); + //KPrintF("STC_SHUTDOWN\n"); + running = FALSE; + break; + + case STC_START: + /* + ** we received a start message with a fractal description. + ** clear the rastport and the line update array and start + ** rendering. + */ + // printf("Task STC_START\n"); + //KPrintF("STC_START\n"); + worktodo = TRUE; + link=NULL; // Start with link=NULL + break; + + case STC_STOP: + /* this message is not used in this example */ + // printf("Task STC_STOP\n"); + //KPrintF("STC_STOP\n"); + worktodo = FALSE; + break; + } + + /* + ** If we received a shutdown message, we do not reply it + ** immediately. First, we need to free our resources. + */ + if (!running) break; + + ReplyMsg((struct Message *)stm); + } + + if (!running) break; + + if (worktodo) + { + //#ifdef ALEXANDER + int LastBuf; + //ULONG signals; + + /* if there is work to do,... + */ + // Fill buffer + if( 0!=PortAudioStreamData->callback(NULL,p1,PortAudioStreamData->framesPerBuffer,0,NULL)) /* Last Buffer */ + { + ConvertU8Samples(p1,PortAudioStreamData->framesPerBuffer); // AHI does not support UINT8-Samples !??? + PortAudioStreamData->StreamActive=0; + worktodo=FALSE; + LastBuf=TRUE; + } + else + { + // more buffers to come + ConvertU8Samples(p1,PortAudioStreamData->framesPerBuffer); // AHI does not support UINT8-Samples !??? + LastBuf=FALSE; + } + + // Play buffer + AHIio->ahir_Std.io_Message.mn_Node.ln_Pri = 75; /* speech, prio of narrator.device */ + AHIio->ahir_Std.io_Command = CMD_WRITE; + AHIio->ahir_Std.io_Data = p1; + AHIio->ahir_Std.io_Length = BufferLength; + AHIio->ahir_Std.io_Offset = 0; + AHIio->ahir_Frequency = (ULONG)PortAudioStreamData->sampleRate; + AHIio->ahir_Type = PortAudioStreamData->AhiSampleType; + AHIio->ahir_Volume = 0x10000; // Full volume + AHIio->ahir_Position = 0x8000; // Centered + AHIio->ahir_Link = link; + SendIO((struct IORequest *) AHIio); + + if(((struct IORequest *) AHIio)->io_Error!=0) + { + printf("io_Error=%lx\n",((struct IORequest *) AHIio)->io_Error); + } + + if(link) { + + // Wait until the last buffer is finished (== the new buffer is started) + /*signals=*/Wait(SIGBREAKF_CTRL_C | (1L << PortAudioStreamData->AHImp->mp_SigBit)); + // Remove the reply and abort on error + if(WaitIO((struct IORequest *) link)) { + SetIoErr(ERROR_WRITE_PROTECTED); + // break; + worktodo=FALSE; // AF + + } + } + + // Check for end-of-sound, and wait until it is finished before aborting + if(LastBuf) { + WaitIO((struct IORequest *) AHIio); + // break; + worktodo=FALSE; // AF + } + + link = AHIio; + + // Swap buffer and request pointers, and restart + tmpBuf = p1; + p1 = p2; + p2 = tmpBuf; + + tmpReq = AHIio; + AHIio = AHIio2; + AHIio2 = tmpReq; + //#endif + } + else + { + /* We have nothing to do, just sit quietly and wait for something to happen */ + //KPrintF("Nothing to do\n"); + WaitPort(st->st_Port); + } + } + + //KPrintF("stm=%lx\n",stm); + //Error=paNoError; + // return;// Error; +/* + if(global_benchmark_flag) // if Benchmarking was done + { + printf("%s, Average BufferTime %lums, Max Buffertime %lums, (Buffer is %lums), Compiled for " __CPU__ " " __FPU__ "\n",global_ProgramName,CallbackTime/CallBackCount,CallBackMaxTime,(ULONG)(global_bufsize_factor*512*1000/PortAudioStreamData->sampleRate)); + } +*/ + //KPrintF("Calling DeletePort st->st_Port\n"); + DeletePort(st->st_Port); + st->st_Port=NULL; + } + else // st->st_Port = CreateMsgPort() failed + { + printf(" Subtask CreateMsgPort() failed\n"); + //Error=paInsufficientMemory; + } + //KPrintF("Calling CloseDevice\n"); + CloseDevice((struct IORequest*)PortAudioStreamData->AHIio); + PortAudioStreamData->device=1; + } + else + { + printf(" Could not open " AHINAME " version 4\n"); + //Error=paDeviceUnavailable; + } + + //KPrintF("Calling DeletePortStartStop\n"); + DeletePort(PortAudioStreamData->portStartStop); + PortAudioStreamData->portStartStop=NULL; + } + else + { + printf(" Could not create portStartStop\n"); + //Error=paInsufficientMemory; + } + //KPrintF("Calling DeleteAHImp\n"); + DeletePort(PortAudioStreamData->AHImp); + PortAudioStreamData->AHImp=NULL; + + } + else + { + printf(" Could not create AHImp\n"); + //Error=paInsufficientMemory; + } + + // Error uebergeben? + //KPrintF("Calling ExitSubtask. stm=%lx\n",(ULONG)stm); + ExitSubTask(st,stm); + } +} + + +/* ##################################################################################################### */ + +PortAudioStream *GlobalPaStreamPtr_ahi=NULL; /* used for atexit(). Functions there have void parameter -> global Pointer needed */ + + +/* + Pa_StartStream() and Pa_StopStream() begin and terminate audio processing. + Pa_StopStream() waits until all pending audio buffers have been played. + Pa_AbortStream() stops playing immediately without waiting for pending + buffers to complete. + */ + +PaError Pa_StartStream_ahidev( PortAudioStream *stream ) +{ + int Error; + // KPrintF("%s() called\n",__FUNCTION__); + //KPrintF("Zeile %ld\n",__LINE__); + if(stream) + { + // printf(" %s called for Stream %u\n",__FUNCTION__,((PortAudioStreamStruct*)stream)->AF_StreamID); + ((PortAudioStreamStruct*)stream)->StreamActive=1; + SendSubTaskMsg(((PortAudioStreamStruct*)stream)->st,STC_START,NULL); + //KPrintF("Zeile %ld\n",__LINE__); + Error=paNoError; + } + else + { + // printf(" %s called with NULL-Ptr\n",__FUNCTION__); + Error=paBadStreamPtr; + + } + + return Error; +} + +/* ########################################################################## */ + + +//PaError Pa_StopStream( PortAudioStream *stream ); + +PaError Pa_AbortStream_ahidev( PortAudioStream *stream ) +{ + // KPrintF("%s() called\n",__FUNCTION__); + // printf(" %s called for Stream %u\n",__FUNCTION__,((PortAudioStreamStruct*)stream)->AF_StreamID); + //KPrintF("Zeile %ld\n",__LINE__); + ((PortAudioStreamStruct*)stream)->StreamActive=0; + return paNoError; +} + +/* ########################################################################## */ +/* + Pa_StreamActive() returns one when the stream is playing audio, + zero when not playing, or a negative error number if the + stream is invalid. + The stream is active between calls to Pa_StartStream() and Pa_StopStream(), + but may also become inactive if the callback returns a non-zero value. + In the latter case, the stream is considered inactive after the last + buffer has finished playing. + */ + + +PaError Pa_StreamActive_ahidev( PortAudioStream *stream ) +{ + // KPrintF("%s() called\n",__FUNCTION__); + + if(stream) + { + // printf(" %s called for Stream %u\n returning %u\n",__FUNCTION__,((PortAudioStreamStruct*)stream)->AF_StreamID,((PortAudioStreamStruct*)stream)->StreamActive); + //KPrintF("Zeile %ld\n",__LINE__); + return ((PortAudioStreamStruct*)stream)->StreamActive; //paNoError; + } + else + { + // printf(" %s called with NULL-Ptr\n",__FUNCTION__); + // printf(" returning paBadStreamPtr\n"); + //KPrintF("Zeile %ld\n",__LINE__); + return paBadStreamPtr; // <0 is error + + } +} + +/* ########################################################################## */ +/* + Pa_OpenDefaultStream() is a simplified version of Pa_OpenStream() that + opens the default input and/or ouput devices. Most parameters have + identical meaning to their Pa_OpenStream() counterparts, with the following + exceptions: + + If either numInputChannels or numOutputChannels is 0 the respective device + is not opened (same as passing paNoDevice in the device arguments to Pa_OpenStream() ) + + sampleFormat applies to both the input and output buffers. + */ + + + +PaError Pa_OpenDefaultStream_ahidev( PortAudioStream** stream, + int numInputChannels, + int numOutputChannels, + PaSampleFormat sampleFormat, + double sampleRate, + unsigned long framesPerBuffer, + unsigned long numberOfBuffers, + PortAudioCallback *callback, + void *userData ) +{ + //KPrintF("Zeile %ld\n",__LINE__); + // KPrintF("%s() called\n",__FUNCTION__); + /* + File_ahi=fopen("Samples","w"); + if(!File_ahi) + { + printf("Kann File nicht oeffnen\n"); + return paInternalError; + } + */ + + static unsigned int StreamNr=1; + PortAudioStreamStruct* StreamStruct; + int Error=paInternalError; + + // printf(" %s called\n",__FUNCTION__); + // printf(" numInputChannels=%d\n",numInputChannels); + // printf(" numOutputChannels=%d\n",numOutputChannels); + // printf(" sampleFormat=%lu (%u bytes)\n",sampleFormat,Pa_GetSampleSize(sampleFormat)); + // printf(" sampleRate=%f\n",sampleRate); + // printf(" framesPerBuffer=%lu\n",framesPerBuffer); // a frame is numOutputChannels * BytesPerSample + // printf(" numberOfBuffers=%lu\n",numberOfBuffers); // this is only a suggestion how many buffers to use, e.g double buffering + // printf(" userData=$%p\n",userData); + + + StreamStruct=(PortAudioStreamStruct*)malloc(sizeof(PortAudioStreamStruct)); + if(StreamStruct) + { + //KPrintF("Zeile %ld\n",__LINE__); + memset(StreamStruct,0,sizeof(PortAudioStreamStruct)); /* initilize all entries */ + StreamStruct->device=1; /* device must be initialized to !=0 (for 0 is success) */ + + // printf(" Setting Stream to %u\n",StreamNr); + StreamStruct->AF_StreamID=StreamNr; + StreamNr++; + + StreamStruct->callback=callback; // store ptr to callback function + StreamStruct->framesPerBuffer=framesPerBuffer;//*global_bufsize_factor; // AF Test mit n mal 512 Byte Puffern + StreamStruct->numInputChannels=numInputChannels; + StreamStruct->numOutputChannels=numOutputChannels; + StreamStruct->sampleFormat=sampleFormat; + StreamStruct->sampleRate=sampleRate; + StreamStruct->AhiSampleType=getAHISampleType(sampleFormat); + + + // ######################################## + + *stream=StreamStruct; + + GlobalPaStreamPtr_ahi=StreamStruct; /* in case of CTRL-C atexit()-Functions are void so a global pointer is needed */ + + //KPrintF("Zeile %ld\n",__LINE__); + + + /* Allocate two Audio Buffers in FastMem for Espeak-16Bit-Samples */ + StreamStruct->FastMemBuf1=(SHORT*)AllocMem(StreamStruct->framesPerBuffer*Pa_GetSampleSize(StreamStruct->sampleFormat),MEMF_PUBLIC); + //KPrintF("Allocating %lu Bytes for FastMemBuf1, Ptr=$%08lx\n",(ULONG)StreamStruct->framesPerBuffer*Pa_GetSampleSize(StreamStruct->sampleFormat),(ULONG)StreamStruct->FastMemBuf1); + if(StreamStruct->FastMemBuf1) + { + //KPrintF("Zeile %ld\n",__LINE__); + + StreamStruct->FastMemBuf2=(SHORT*)AllocMem(StreamStruct->framesPerBuffer*Pa_GetSampleSize(StreamStruct->sampleFormat),MEMF_PUBLIC); + if(StreamStruct->FastMemBuf2) + { + //KPrintF("Zeile %ld\n",__LINE__); + + /* Allocate two audio IO Blocks */ + StreamStruct->AHIio=(struct AHIRequest*)AllocMem(sizeof(struct AHIRequest),MEMF_PUBLIC|MEMF_CLEAR); + if(StreamStruct->AHIio) + { + //KPrintF("Zeile %ld, AHIio=%08lx\n",__LINE__,StreamStruct->AHIio); + + StreamStruct->AHIio2=(struct AHIRequest*)AllocMem(sizeof(struct AHIRequest),MEMF_PUBLIC|MEMF_CLEAR); + if(StreamStruct->AHIio2) + { + //KPrintF("Zeile %ld\n",__LINE__); + + StreamStruct->AIOptrStartStop=(struct AHIRequest*)AllocMem(sizeof(struct AHIRequest),MEMF_PUBLIC|MEMF_CLEAR); + if(StreamStruct->AIOptrStartStop) + { + //KPrintF("Zeile %ld\n",__LINE__); + + StreamStruct->st = SpawnSubTask("EspeakAudioTask_AHI",SamAudioTask_AHI,StreamStruct); + if (StreamStruct->st) + { + //KPrintF("Zeile %ld\n",__LINE__); + + Error=paNoError; + return Error; + } + Error=paInternalError; + } + else + { + printf(" not enough memory for allocating AIOptrStartStop\n"); + Error=paInsufficientMemory; + } + FreeMem(StreamStruct->AHIio2,sizeof(struct AHIRequest)); + StreamStruct->AHIio2=NULL; + } + else + { + printf(" not enough memory for allocating AHIio2\n"); + Error=paInsufficientMemory; + } + FreeMem(StreamStruct->AHIio,sizeof(struct AHIRequest)); + StreamStruct->AHIio=NULL; + } + else + { + printf(" not enough memory for allocating AHIio\n"); + Error=paInsufficientMemory; + } + FreeMem(StreamStruct->FastMemBuf2,StreamStruct->framesPerBuffer*Pa_GetSampleSize(StreamStruct->sampleFormat)); + StreamStruct->FastMemBuf2=NULL; + } + else + { + printf(" Could not allocate FastMemBuf2 (%lu Bytes)\n",StreamStruct->framesPerBuffer*Pa_GetSampleSize(StreamStruct->sampleFormat)); + Error=paInsufficientMemory; + } + FreeMem(StreamStruct->FastMemBuf1,StreamStruct->framesPerBuffer*Pa_GetSampleSize(StreamStruct->sampleFormat)); + StreamStruct->FastMemBuf1=NULL; + } + else + { + printf(" Could not allocate FastMemBuf1 (%lu Bytes)\n",StreamStruct->framesPerBuffer*Pa_GetSampleSize(StreamStruct->sampleFormat)); + Error=paInsufficientMemory; + } + + free(StreamStruct); + StreamStruct=NULL; + *stream=NULL; + GlobalPaStreamPtr_ahi=NULL; /* in case of CTRL-C atexit()-Functions are void so a global pointer is needed */ + + } + else + { + printf(" not enough memory for allocating stream %u\n",StreamNr); + Error=paInsufficientMemory; + } + + // KPrintF("Finished %s\n",__FUNCTION__); + return Error; +} + + +/* ########################################################################## */ +/* + Pa_CloseStream() closes an audio stream, flushing any pending buffers. + */ + +PaError Pa_CloseStream_ahidev( PortAudioStream *stream ) +{ + //KPrintF("%s() called\n",__FUNCTION__); + //KPrintF("Zeile %ld\n",__LINE__); + PortAudioStreamStruct *StreamStruct=(PortAudioStreamStruct*)stream; + + if(stream) + { + // printf(" %s called for Stream %u\n",__FUNCTION__,StreamStruct->AF_StreamID); + + if(StreamStruct->st) + { + KillSubTask(StreamStruct->st); + StreamStruct->st=NULL; + } + + if(StreamStruct->device==0) + { + CloseDevice((struct IORequest*)StreamStruct->AHIio); + StreamStruct->device=1; + } + + if(StreamStruct->portStartStop) + { + DeletePort(StreamStruct->portStartStop); + StreamStruct->portStartStop=0; + } + + if(StreamStruct->AHImp) + { + DeletePort(StreamStruct->AHImp); + StreamStruct->AHImp=0; + } + + if(StreamStruct->AIOptrStartStop) + { + FreeMem(StreamStruct->AIOptrStartStop,sizeof(struct AHIRequest)); + StreamStruct->AIOptrStartStop=NULL; + } + + if(StreamStruct->AHIio2) + { + FreeMem(StreamStruct->AHIio2,sizeof(struct AHIRequest)); + StreamStruct->AHIio2=NULL; + } + + if(StreamStruct->AHIio) + { + FreeMem(StreamStruct->AHIio,sizeof(struct AHIRequest)); + StreamStruct->AHIio=NULL; + } + + if(StreamStruct->FastMemBuf2) + { + FreeMem(StreamStruct->FastMemBuf2,StreamStruct->framesPerBuffer*Pa_GetSampleSize(StreamStruct->sampleFormat)); + StreamStruct->FastMemBuf2=NULL; + } + + if(StreamStruct->FastMemBuf1) + { + FreeMem(StreamStruct->FastMemBuf1,StreamStruct->framesPerBuffer*Pa_GetSampleSize(StreamStruct->sampleFormat)); + StreamStruct->FastMemBuf1=NULL; + } + + free(StreamStruct); + GlobalPaStreamPtr_ahi=NULL; /* in case of CTRL-C atexit()-Functions are void so a global pointer is needed */ + + + // printf(" returning paNoError\n"); + return paNoError; + } + else + { + // printf(" %s called with NULL-Ptr\n",__FUNCTION__); + // printf(" returning paBadStreamPtr\n"); + return paBadStreamPtr; // <0 is error + + } +/* + if(File_ahi) + { + fclose(File_ahi); + File_ahi=NULL; + } +*/ +} + + +/* ########################################################################## */ +/* + Pa_Initialize() is the library initialisation function - call this before + using the library. + */ + + +PaError Pa_Initialize_ahidev( void ) +{ + int Error; + //KPrintF("Zeile %ld\n",__LINE__); + // printf(" %s called\n",__FUNCTION__); + // KPrintF("%s() called\n",__FUNCTION__); + + Error=paNoError; + + return Error; +} + + + +// ############################################################################## +// not needed by espeak but used by myself, AF 18.May2017 + +/* + Return size in bytes of a single sample in a given PaSampleFormat + or paSampleFormatNotSupported. + */ +PaError Pa_GetSampleSize_ahidev( PaSampleFormat format ) +{ + // KPrintF("%s() called\n",__FUNCTION__); + //KPrintF("Zeile %ld\n",__LINE__); + switch (format) + { + case paFloat32 : return 4; /*always available*/ + case paInt16 : return 2; /*always available*/ + case paInt32 : return 4; /*always available*/ + case paInt24 : return 6; + case paPackedInt24 : return 6; + case paInt8 : return 1; + case paUInt8 : return 1; /* unsigned 8 bit, 128 is "ground" */ + default : return paSampleFormatNotSupported; + } +} + + + +STATIC_FUNC ULONG getAHISampleType(PaSampleFormat format ) +{ + //KPrintF("Zeile %ld\n",__LINE__); + // KPrintF("%s() called\n",__FUNCTION__); + switch (format) + { + // case paFloat32 : return ; /*always available*/ + case paInt16 : return AHIST_M16S; /* Mono, 16 bit signed (WORD) */ /*always available*/ + case paInt32 : return AHIST_M32S; /* Mono, 32 bit signed (LONG) */ /*always available*/ + // case paInt24 : return ; + // case paPackedInt24 : return ; + case paInt8 : return AHIST_M8S; /* Mono, 8 bit signed (BYTE) */ + //case paUInt8 : return AHIST_M8U; /* OBSOLETE! */ /* unsigned 8 bit, 128 is "ground" Is not supported by AHI !?*/ + case paUInt8 : return AHIST_M8S; /* set tp SIGNED 8 bit instead and convert buffer later */ + default : return AHIE_BADSAMPLETYPE; /* Unknown/unsupported sample type */; + } + +} + + +// ############################################################################## +/* reads 16Bit Signed Samples from Source and writes 8Bit Signed Samples to Dest. */ +/* 16 Bit Samples must be BIG_ENDIAN */ +/* SampleCount Samples will be read */ +/* SampleCount must be multiple of 2 */ +/* Returns number of copied samples */ +/* AF, 15.76.2017 */ + +//static UWORD Convert16SSamples(SHORT *Source16S, BYTE *Dest8S, ULONG SampleCount) +//{ +// UWORD i=0; +// ULONG *SourcePtr=(ULONG*)Source16S; /* we read 2 16Bit-Samples at once */ +// USHORT *DestPtr=(USHORT*)Dest8S; /* we write 2 8Bit-Samples at once */ +// ULONG SourceSamples; +// USHORT DestSamples; +// //KPrintF("Zeile %ld\n",__LINE__); +// if(SampleCount%2) +// { +// printf("%s() SampleCount %lu is not even!\n",__FUNCTION__,SampleCount); + /* we read probably one bad sample but continue anyway */ +// } + +// for(;i>16) | ((SourceSamples &0xff00) >> 8); /* extract the two High-Bytes */ +// *DestPtr++=DestSamples; + + /*printf("SourceSamples=0x%0lx, DestSamples=0x%0hx\n",SourceSamples,DestSamples);*/ +// } +// return i*2; +//} + + + +/* used for atexit(). Therefore void parameter -> global Pointer needed */ +void Abort_Pa_CloseStream_ahidev (void) +{ + //KPrintF("Zeile %ld\n",__LINE__); + if(GlobalPaStreamPtr_ahi) + { + // KPrintF("%s() called with Stream=$%08lx\n",__FUNCTION__,GlobalPaStreamPtr_ahi); + Pa_CloseStream(GlobalPaStreamPtr_ahi); + GlobalPaStreamPtr_ahi=NULL; + } + else + { + // KPrintF("%s() called but nothing to do\n",__FUNCTION__); + } +} + + + diff --git a/src/amiga/portaudio/portaudio_ahidev.h b/src/amiga/portaudio/portaudio_ahidev.h new file mode 100644 index 00000000..3b7d7361 --- /dev/null +++ b/src/amiga/portaudio/portaudio_ahidev.h @@ -0,0 +1,42 @@ +/*************************************************************************** + * Copyright (C) 2017 by Alexander Fritsch * + * email: selco@t-online.de * + ***************************************************************************/ + +/* + * * portaudio_ahidev.h + * + * Created on: Nov 28, 2017 + * Author: developer + */ + +#ifndef SRC_AMIGA_PORTAUDIO_PORTAUDIO_AHIDEV_H_ +#define SRC_AMIGA_PORTAUDIO_PORTAUDIO_AHIDEV_H_ + + + +#include "../portaudio18.h" + +/* prototypes to be used in general portaudio.cpp only */ + +PaError Pa_StartStream_ahidev( PortAudioStream *stream ); +PaError Pa_AbortStream_ahidev( PortAudioStream *stream ); +PaError Pa_StreamActive_ahidev( PortAudioStream *stream ); +PaError Pa_OpenDefaultStream_ahidev( PortAudioStream** stream, + int numInputChannels, + int numOutputChannels, + PaSampleFormat sampleFormat, + double sampleRate, + unsigned long framesPerBuffer, + unsigned long numberOfBuffers, + PortAudioCallback *callback, + void *userData ); +PaError Pa_CloseStream_ahidev( PortAudioStream *stream ); +PaError Pa_Initialize_ahidev( void ); +PaError Pa_GetSampleSize_ahidev( PaSampleFormat format ); +void Abort_Pa_CloseStream_ahidev (void); + +extern unsigned int g_AHI_Unit; + + +#endif /* SRC_AMIGA_PORTAUDIO_PORTAUDIO_AHIDEV_H_ */ diff --git a/src/amiga/portaudio/portaudio_audev.c b/src/amiga/portaudio/portaudio_audev.c new file mode 100644 index 00000000..331785d3 --- /dev/null +++ b/src/amiga/portaudio/portaudio_audev.c @@ -0,0 +1,1157 @@ +/*************************************************************************** + * Copyright (C) 2017 by Alexander Fritsch * + * email: selco@t-online.de * + ***************************************************************************/ + +/* Amiga audio.device part */ + +#include "../portaudio18.h" +#include +#include + +/* AF, Gwd, 5.May 2017 */ + +#include +#include "subtask_support.h" + +#include + +#include +#include + +#include /* for CreatePort */ +#include +#include +#include // sleep + +#include "portaudio_audev.h" + +#ifdef mc68060 +#define __CPU__ "mc68060" +#elif defined mc68040 +#define __CPU__ "mc68040" +#elif defined mc68030 +#define __CPU__ "mc68030" +#elif defined mc68020 +#define __CPU__ "mc68020" +#elif defined mc68000 +#define __CPU__ "mc68000" +#else +#define __CPU__ "???????" +#endif + +#ifdef __HAVE_68881__ +#define __FPU__ "mc68881" +#else +#define __FPU__ "" +#endif + +/*extern "C"*/ LONG KPrintF(STRPTR format, ...); + + +#include +#define CIAA 0xBFE001 /* Address of CIAA chip */ + +// 0==bright LED, Filter=0n +// return 1 if bit is NOT set, i.e. Filter is on +unsigned int getAudioFilterState(void) +{ + struct CIA *cia = (struct CIA *) CIAA; + unsigned int Result= ((cia->ciapra ^ CIAF_LED) & CIAF_LED) ? 1: 0; +// KPrintF("Filter is %s\n",Result ? "On":"Off"); + return Result; +} + +void setAudioFilterState(unsigned int val) +{ + struct CIA *cia = (struct CIA *) CIAA; + unsigned char cia_value=cia->ciapra; + + cia_value &= ~CIAF_LED; + cia_value |= val ? 0: CIAF_LED; + cia->ciapra=cia_value; + +// KPrintF("%s(%ld) -> ",__FUNCTION__,val); + getAudioFilterState(); +} + + +//UBYTE chans[] ={1,2,4,8}; /* get any of the four channels RKRM Audio-example */ +UBYTE chans[] ={3,5,10,12}; /* get a pair of stereo channels, RKRM Devices */ +//UBYTE chans[] ={1,8}; /* test, nur rechts */ +//UBYTE chans[] ={2,4}; /* test, nur links */ + +typedef struct +{ + int StreamActive; + unsigned int AF_StreamID; // just a number to see which stream is referred to + + struct SubTask *st; + struct SignalSemaphore sema; /* data item protection */ + + int numInputChannels; + int numOutputChannels; // 1 for mono, 2 for stereo + PaSampleFormat sampleFormat; + double sampleRate; + unsigned long framesPerBuffer; // a frames is one complete sample from each channel + unsigned long numberOfBuffers; // suggestion for (double) bufering + PortAudioCallback *callback; + void *userData; + unsigned int clock; // Amiga Systemclock 3546895 for PAL, 3579545 for NTSC */ + unsigned long speed; // clock / samplerate + struct IOAudio *AIOptr1; // four audio I/O blocks + struct IOAudio *AIOptr1_2; // second channel + struct IOAudio *AIOptr2; + struct IOAudio *AIOptr2_2; // second channel + struct IOAudio *AIOptrStartStop;// for CMD_START and CMD_STOP + struct MsgPort *port1; + struct MsgPort *port1_2; + struct MsgPort *port2; + struct MsgPort *port2_2; + struct MsgPort *portStartStop; + ULONG device; // Audio device handle + BYTE *ChipMemBuf1; // Amiga-Audiobuffer + BYTE *ChipMemBuf2; // Amiga-Audiobuffer + SHORT *FastMemBuf1; // Espeak-AudioBuffer used in Callback + SHORT *FastMemBuf2; // Espeak-AudioBuffer used in Callback + unsigned int LeftChannel; // left Audiochannel we got allocated in OpenDevice() or 0 + unsigned int RightChannel; // right Audiochannel we got allocated in OpenDevice() or 0 + unsigned int LP_FilterSate; // stores old state of audop LP-Filter + +}PortAudioStreamStruct; + + + +// This function writes the channel-Bit to io.Unit. It saves some pointer magic +// old code was +// (ULONG)PortAudioStreamData->AIOptr1 ->ioa_Request.io_Unit &=0xf0; (ULONG)&PortAudioStreamData->AIOptr1 ->ioa_Request.io_Unit |= PortAudioStreamData->LeftChannel; /* lower 4 Bits contain ONE channel bit */ +// but does not compile under gcc6 nay more +void SetAudioUnit(struct IOAudio *AIOptr,unsigned int Channel) +{ + ULONG Temp; + Temp= (ULONG) AIOptr->ioa_Request.io_Unit; + Temp&=0xf0; + Temp|=Channel; + AIOptr->ioa_Request.io_Unit =(struct Unit*)Temp; + +} + + +STATIC_FUNC UWORD Convert8USamples(UBYTE *Source8U, BYTE *Dest8S, ULONG SampleCount); /* reads 16Bit Signed Samples from Source and writes 8Bit Signed Samples to Dest. DestLen Samples will be read */ + + + +VOID /*__asm*/ /*__saveds*/ SamAudioTask(VOID) +{ + + // KPrintF("%s() called\n",__FUNCTION__); + + { + // do not use ExecBase via a4 yet + struct Library * SysBase = *(struct Library **)4; + struct Task * task = FindTask(0); + task->tc_UserData = (APTR)((struct Process *)task)->pr_CIS; // the main task put a4 via NP_Input into pr_CIS + __restore_a4(); // get A4 from there. Now we can access static and global data via A4 ! + + // now fix CIS to zero or allocate something or ... + ((struct Process *)task)->pr_CIS = 0; + } + + struct Task *me = FindTask(NULL); + struct SubTask *st; + struct SubTaskMsg *stm; + + /* + ** Wait for our startup message from the SpawnSubTask() function. + */ + + WaitPort(&((struct Process *)me)->pr_MsgPort); + stm = (struct SubTaskMsg *)GetMsg(&((struct Process *)me)->pr_MsgPort); + st = (struct SubTask *)stm->stm_Parameter; + + + + + { + // struct Data *data = (struct Data *)st->st_Data; + BOOL running = TRUE; + BOOL worktodo = FALSE; + + PortAudioStreamStruct *PortAudioStreamData=(PortAudioStreamStruct*)(st->st_Data); + //int Error=paInternalError; + + /* Make four Reply-Ports */ + PortAudioStreamData->port1=CreatePort(0,0); + if(PortAudioStreamData->port1) + { + PortAudioStreamData->port1_2=CreatePort(0,0); + if(PortAudioStreamData->port1_2) + { + PortAudioStreamData->port2=CreatePort(0,0); + if(PortAudioStreamData->port2) + { + PortAudioStreamData->port2_2=CreatePort(0,0); + if(PortAudioStreamData->port2_2) + { + PortAudioStreamData->portStartStop=CreatePort(0,0); + if(PortAudioStreamData->portStartStop) + { + + /* Now Open Audio Device */ + // KPrintF("Attempting to open Audio.device\n"); + /* set up audio I/O block for channel */ + /* allocation and Open the audio.device */ + PortAudioStreamData->AIOptr1->ioa_Request.io_Message.mn_ReplyPort=PortAudioStreamData->port1; + PortAudioStreamData->AIOptr1->ioa_Request.io_Message.mn_Node.ln_Pri=127; /* no stealing */ + PortAudioStreamData->AIOptr1->ioa_Request.io_Message.mn_Length=sizeof(struct IOAudio); + + PortAudioStreamData->AIOptr1->ioa_AllocKey=0; + PortAudioStreamData->AIOptr1->ioa_Data=chans; + PortAudioStreamData->AIOptr1->ioa_Length=sizeof(chans); + + + PortAudioStreamData->device=OpenDevice((CONST_STRPTR)AUDIONAME,0L,(struct IORequest*)PortAudioStreamData->AIOptr1,0L); + + if(PortAudioStreamData->device==0) + { + UBYTE GotChannels; + + /* Set Up Audio IO Blocks for Sample Playing */ + //printf("AllocKey is 0x%02u\n",PortAudioStreamData->AIOptr1->ioa_AllocKey); + //printf("ioa_Request.io_Unit=0x%02u\n",(UBYTE)PortAudioStreamData->AIOptr1->ioa_Request.io_Unit); /* the channels I got are in ioUnit, lower 4 bits. */ + + + GotChannels=((/*UBYTE*/ULONG)PortAudioStreamData->AIOptr1->ioa_Request.io_Unit) & 0x0f; /* the channels I got are in ioUnit, lower 4 bits. */ + if(GotChannels & 0x02) PortAudioStreamData->LeftChannel=0x02; + else if(GotChannels & 0x04) PortAudioStreamData->LeftChannel=0x04; + else PortAudioStreamData->LeftChannel=0; + + if(GotChannels & 0x01) PortAudioStreamData->RightChannel=0x01; + else if(GotChannels & 0x08) PortAudioStreamData->RightChannel=0x08; + else PortAudioStreamData->RightChannel=0; + + //printf("Left Channel: %u\n",PortAudioStreamData->LeftChannel); + //printf("Right Channel: %u\n",PortAudioStreamData->RightChannel); + + PortAudioStreamData->AIOptr1->ioa_Request.io_Command=CMD_WRITE; + PortAudioStreamData->AIOptr1->ioa_Request.io_Flags=ADIOF_PERVOL; + + /* Volume */ + PortAudioStreamData->AIOptr1->ioa_Volume=64; /* (0 thru 64, linear) */ + + /* Period/Cycles */ + PortAudioStreamData->AIOptr1->ioa_Period=(UWORD)PortAudioStreamData->speed; + PortAudioStreamData->AIOptr1->ioa_Cycles=1; + + *(PortAudioStreamData->AIOptr1_2)=*(PortAudioStreamData->AIOptr1); /* Make sure we have the same allocation keys */ + *(PortAudioStreamData->AIOptr2) =*(PortAudioStreamData->AIOptr1); /* Make sure we have the same allocation keys */ + *(PortAudioStreamData->AIOptr2_2)=*(PortAudioStreamData->AIOptr1); /* Make sure we have the same allocation keys */ + *(PortAudioStreamData->AIOptrStartStop)=*(PortAudioStreamData->AIOptr1); /* Make sure we have the same allocation keys */ + /* same channel selected (allocKeys) and same flags */ + /* but different ports... */ + PortAudioStreamData->AIOptr1 ->ioa_Request.io_Message.mn_ReplyPort=PortAudioStreamData->port1; /* Left and right Channels are running exactly synchronous. They can therefore use the same port */ + PortAudioStreamData->AIOptr1_2->ioa_Request.io_Message.mn_ReplyPort=PortAudioStreamData->port1_2; + PortAudioStreamData->AIOptr2 ->ioa_Request.io_Message.mn_ReplyPort=PortAudioStreamData->port2; + PortAudioStreamData->AIOptr2_2->ioa_Request.io_Message.mn_ReplyPort=PortAudioStreamData->port2_2; + PortAudioStreamData->AIOptrStartStop->ioa_Request.io_Message.mn_ReplyPort=PortAudioStreamData->portStartStop; + /* and different Channels in ioUnit -> CMD_WRITE is a single channel command */ + + // (ULONG)PortAudioStreamData->AIOptr1 ->ioa_Request.io_Unit &=0xf0; (ULONG)&PortAudioStreamData->AIOptr1 ->ioa_Request.io_Unit |= PortAudioStreamData->LeftChannel; /* lower 4 Bits contain ONE channel bit */ + // (ULONG)PortAudioStreamData->AIOptr1_2->ioa_Request.io_Unit &=0xf0; (ULONG)PortAudioStreamData->AIOptr1_2->ioa_Request.io_Unit |= PortAudioStreamData->RightChannel; + // (ULONG)PortAudioStreamData->AIOptr2 ->ioa_Request.io_Unit &=0xf0; (ULONG)PortAudioStreamData->AIOptr2 ->ioa_Request.io_Unit |= PortAudioStreamData->LeftChannel; + // (ULONG)PortAudioStreamData->AIOptr2_2->ioa_Request.io_Unit &=0xf0; (ULONG)PortAudioStreamData->AIOptr2_2->ioa_Request.io_Unit |= PortAudioStreamData->RightChannel; + // use new function SetAudioUnit() instead + SetAudioUnit(PortAudioStreamData->AIOptr1, PortAudioStreamData->LeftChannel); /* lower 4 Bits contain ONE channel bit */ + SetAudioUnit(PortAudioStreamData->AIOptr1_2, PortAudioStreamData->RightChannel); /* lower 4 Bits contain ONE channel bit */ + SetAudioUnit(PortAudioStreamData->AIOptr2, PortAudioStreamData->LeftChannel); /* lower 4 Bits contain ONE channel bit */ + SetAudioUnit(PortAudioStreamData->AIOptr2_2, PortAudioStreamData->RightChannel); /* lower 4 Bits contain ONE channel bit */ + + + + // Data... + + if ((st->st_Port = CreateMsgPort())) + { + /* + ** Reply startup message, everything ok. + ** Note that if the initialization fails, the code falls + ** through and replies the startup message with a stm_Result + ** of 0 after a Forbid(). This tells SpawnSubTask() that the + ** sub task failed to run. + */ + + /* variables are declared here because they should be initialized to Zero */ + /* in the for loop they would become initialized at the beginning of every turn - which is wrong */ + struct IOAudio *Aptr=NULL; /* for double buffer switching */ + struct MsgPort *port=NULL; /* for double buffer switching */ + struct MsgPort *port_2=NULL; /* for double buffer switching for the second audio channel (we do 2-channel(MONO) playback)*/ + BYTE *ChipMemBuf=NULL; /* Amiga-Audiobuffer for double buffer switching */ + SHORT *FastMemBuf=NULL; /* Espeak-AudioBuffer used in Callback for double buffer switching */ + + //ULONG CallbackTime=0; /* For Callback benchmarking */ + //ULONG CallBackCount=0; + //ULONG CallBackMaxTime=0; + + stm->stm_Result = TRUE; + ReplyMsg((struct Message *)stm); + // Ok, all opened sucessfully + // KPrintF("Opened Audio.device successfully\n"); + + /* + ** after the sub task is up and running, we go into + ** a loop and process the messages from the main task. + */ + + for (;;) + { + while ((stm = (struct SubTaskMsg *)GetMsg(st->st_Port))) + { + switch (stm->stm_Command) + { + case STC_SHUTDOWN: + /* + ** This is the shutdown message from KillSubTask(). + */ + // printf("Task STC_SHUTDOWN\n"); + //KPrintF("STC_SHUTDOWN\n"); + + running = FALSE; + break; + + case STC_START: + /* + ** we received a start message with a fractal description. + ** clear the rastport and the line update array and start + ** rendering. + */ + // printf("Task STC_START\n"); + //KPrintF("STC_START\n"); + + worktodo = TRUE; + + /* read two buffers. cannot fail. (just end of data but that does not matter here) */ + PortAudioStreamData->callback(NULL,PortAudioStreamData->FastMemBuf1,PortAudioStreamData->framesPerBuffer,0,NULL); + + Convert8USamples(PortAudioStreamData->FastMemBuf1, PortAudioStreamData->ChipMemBuf1 ,PortAudioStreamData->framesPerBuffer); + PortAudioStreamData->AIOptr1->ioa_Length=PortAudioStreamData->framesPerBuffer; + PortAudioStreamData->AIOptr1->ioa_Data=(UBYTE*)PortAudioStreamData->ChipMemBuf1; + + PortAudioStreamData->AIOptr1_2->ioa_Length=PortAudioStreamData->framesPerBuffer; /* second channel */ + PortAudioStreamData->AIOptr1_2->ioa_Data=(UBYTE*)PortAudioStreamData->ChipMemBuf1; /* second channel */ + + + + PortAudioStreamData->callback(NULL,PortAudioStreamData->FastMemBuf2,PortAudioStreamData->framesPerBuffer,0,NULL); + Convert8USamples(PortAudioStreamData->FastMemBuf2, PortAudioStreamData->ChipMemBuf2 ,PortAudioStreamData->framesPerBuffer); + PortAudioStreamData->AIOptr2->ioa_Length=PortAudioStreamData->framesPerBuffer; + PortAudioStreamData->AIOptr2->ioa_Data=(UBYTE*)PortAudioStreamData->ChipMemBuf2; + + PortAudioStreamData->AIOptr2_2->ioa_Length=PortAudioStreamData->framesPerBuffer; /* second channel */ + PortAudioStreamData->AIOptr2_2->ioa_Data=(UBYTE*)PortAudioStreamData->ChipMemBuf2; /* second channel */ + + /* Synchonized Start of both stereo channels -> CMD_STOP, CMD_WRITE, CMD_START */ + PortAudioStreamData->AIOptrStartStop->ioa_Request.io_Command=CMD_STOP; + DoIO((struct IORequest*)PortAudioStreamData->AIOptrStartStop); /* synchronous call, cares about complete-message */ + + /* Start playback */ + BeginIO((struct IORequest*)PortAudioStreamData->AIOptr1); + BeginIO((struct IORequest*)PortAudioStreamData->AIOptr1_2); + BeginIO((struct IORequest*)PortAudioStreamData->AIOptr2); + BeginIO((struct IORequest*)PortAudioStreamData->AIOptr2_2); + + //KPrintF("AIOptr1=0x%08lx\n",PortAudioStreamData->AIOptr1); + //KPrintF("AIOptr1_2=0x%08lx\n",PortAudioStreamData->AIOptr1_2); + //KPrintF("AIOptr2=0x%08lx\n",PortAudioStreamData->AIOptr2); + //KPrintF("AIOptr2_2=0x%08lx\n",PortAudioStreamData->AIOptr2_2); + + PortAudioStreamData->AIOptrStartStop->ioa_Request.io_Command=CMD_START; + DoIO((struct IORequest*)PortAudioStreamData->AIOptrStartStop); /* synchronous call, cares about complete-message */ + + /* set the double buffer switching */ + Aptr=PortAudioStreamData->AIOptr1; + port=PortAudioStreamData->port1; + port_2=PortAudioStreamData->port1_2; + FastMemBuf=PortAudioStreamData->FastMemBuf1; + ChipMemBuf=PortAudioStreamData->ChipMemBuf1; + break; + + case STC_STOP: + /* this message is not used in this example */ + // printf("Task STC_STOP\n"); + //KPrintF("STC_STOP\n"); + worktodo = FALSE; + break; + }// switch + + /* + ** If we received a shutdown message, we do not reply it + ** immediately. First, we need to free our resources. + */ + if (!running) break; + + ReplyMsg((struct Message *)stm); + } + + if (!running) + { + break; // while + } + + if (worktodo) + { + /* if there is work to do,... + */ + /* + void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ); + */ + + struct Message *msg; + //ULONG wakebit; + + /*wakebit=*/Wait(1 << port->mp_SigBit); + while((msg=GetMsg(port))==0) + { + }; + //KPrintF("GetMsg() returned 0x%08lx\n",msg); + /*wakebit=*/Wait(1 << port_2->mp_SigBit); + while((msg=GetMsg(port_2))==0) // the 2. channel has also finished. Clear that message queue, too + { + }; + + // printf("Callback() called %u\n",count); + if( 0!=PortAudioStreamData->callback(NULL,FastMemBuf,PortAudioStreamData->framesPerBuffer,0,NULL)) /* Last Buffer */ + { + /* we queue this last buffer for playback and wait for the previous one and this one to finish */ + + // printf("Callback() called %u, return != paContinue. End of stream.\n",count); + PortAudioStreamData->StreamActive=0; + worktodo=FALSE; + Convert8USamples(FastMemBuf, ChipMemBuf ,PortAudioStreamData->framesPerBuffer); + BeginIO((struct IORequest*)Aptr); + BeginIO((Aptr==PortAudioStreamData->AIOptr1)?(struct IORequest*)PortAudioStreamData->AIOptr1_2:(struct IORequest*)PortAudioStreamData->AIOptr2_2); /* also corresponding 2. stereo-channel */ + /* Wait for the last two buffers to finish */ + if(Aptr==(struct IOAudio*)PortAudioStreamData->AIOptr1) + { + Aptr=PortAudioStreamData->AIOptr2; + port=PortAudioStreamData->port2; + port_2=PortAudioStreamData->port2_2; + } + else + { + Aptr=PortAudioStreamData->AIOptr1; + port=PortAudioStreamData->port1; + port_2=PortAudioStreamData->port1_2; + } + /*wakebit=*/Wait(1 << port->mp_SigBit); /* wait until last buffer has finished */ + while((msg=GetMsg(port))==0) {}; + /*wakebit=*/Wait(1 << port_2->mp_SigBit); /* wait until last buffer has finished */ + while((msg=GetMsg(port_2))==0) {}; + + if(Aptr==(struct IOAudio*)PortAudioStreamData->AIOptr1) + { + port=PortAudioStreamData->port2; + port_2=PortAudioStreamData->port2_2; + } + else + { + port=PortAudioStreamData->port1; + port_2=PortAudioStreamData->port1_2; + } + /*wakebit=*/Wait(1 << port->mp_SigBit); /* wait until last bufer has finished */ + while((msg=GetMsg(port))==0) {}; + /*wakebit=*/Wait(1 << port_2->mp_SigBit); /* wait until last bufer has finished */ + while((msg=GetMsg(port_2))==0) {}; + } + else /* There are more buffers to come */ + { + //KPrintF("Convert16SSamples($%08lx,$%08lx)\n",(ULONG)PortAudioStreamData->FastMemBuf1, (ULONG)PortAudioStreamData->ChipMemBuf1); + + //fwrite(PortAudioStreamData->FastMemBuf1,PortAudioStreamData->framesPerBuffer,1,File); + Convert8USamples(FastMemBuf, ChipMemBuf ,PortAudioStreamData->framesPerBuffer); + // fwrite(PortAudioStreamData->ChipMemBuf1,PortAudioStreamData->framesPerBuffer,1,File); + BeginIO((struct IORequest*)Aptr); + BeginIO((Aptr==PortAudioStreamData->AIOptr1)?(struct IORequest*)PortAudioStreamData->AIOptr1_2:(struct IORequest*)PortAudioStreamData->AIOptr2_2); /* also corresponding 2. stereo-channel */ + + /* Double buffer switching */ + if(Aptr==(struct IOAudio*)PortAudioStreamData->AIOptr1) + { + Aptr=PortAudioStreamData->AIOptr2; + port=PortAudioStreamData->port2; + port_2=PortAudioStreamData->port2_2; + FastMemBuf=PortAudioStreamData->FastMemBuf2; + ChipMemBuf=PortAudioStreamData->ChipMemBuf2; + } + else + { + Aptr=PortAudioStreamData->AIOptr1; + port=PortAudioStreamData->port1; + port_2=PortAudioStreamData->port1_2; + FastMemBuf=PortAudioStreamData->FastMemBuf1; + ChipMemBuf=PortAudioStreamData->ChipMemBuf1; + } + + } + + /* Since we are very busy working, we do not Wait() for signals. */ + } + else + { + //KPrintF("Nothing to do\n"); + /* We have nothing to do, just sit quietly and wait for something to happen */ + WaitPort(st->st_Port); + } + }//for + + + //KPrintF("stm=%lx\n",stm); + + //Error=paNoError; + // return;// Error; + + /* Wait for sound to finish ALEXANDER */ + PortAudioStreamData->AIOptr1->ioa_Request.io_Command=ADCMD_FINISH; + BeginIO((struct IORequest*)PortAudioStreamData->AIOptr1); + PortAudioStreamData->AIOptr2->ioa_Request.io_Command=ADCMD_FINISH; + BeginIO((struct IORequest*)PortAudioStreamData->AIOptr2); +/* + if(global_benchmark_flag) // if Benchmarking was done + { + printf("%s, Average BufferTime %lums, Max Buffertime %lums, (Buffer is %lums), Compiled for " __CPU__ " " __FPU__ "\n",global_ProgramName,CallbackTime/CallBackCount,CallBackMaxTime,(ULONG)(global_bufsize_factor*512*1000/PortAudioStreamData->sampleRate)); + } +*/ + //KPrintF("Calling DeletePort st->st_Port\n"); + DeletePort(st->st_Port); + st->st_Port=NULL; + } + else // st->st_Port = CreateMsgPort() failed + { + printf(" Subtask CreateMsgPort() failed\n"); + //Error=paInsufficientMemory; + } + //KPrintF("Calling CloseDevice\n"); + CloseDevice((struct IORequest*)PortAudioStreamData->AIOptr1); + PortAudioStreamData->device=1; + } + else + { + printf(" Could not open " AUDIONAME "\n"); + //Error=paDeviceUnavailable; + } + /* --------------------- */ + //KPrintF("Calling DeletePortStartStop\n"); + DeletePort(PortAudioStreamData->portStartStop); + PortAudioStreamData->portStartStop=NULL; + } + else + { + printf(" Could not create portStartStop\n"); + //Error=paInsufficientMemory; + } + //KPrintF("Calling DeletePort2_2\n"); + DeletePort(PortAudioStreamData->port2_2); + PortAudioStreamData->port2_2=NULL; + + } + else + { + printf(" Could not create port2_2\n"); + //Error=paInsufficientMemory; + } + //KPrintF("Calling DeletePort2\n"); + DeletePort(PortAudioStreamData->port2); + PortAudioStreamData->port2=NULL; + } + else + { + printf(" Could not create port2\n"); + //Error=paInsufficientMemory; + } + //KPrintF("Calling DeletePort1_2\n"); + DeletePort(PortAudioStreamData->port1_2); + PortAudioStreamData->port1_2=NULL; + } + else + { + printf(" Could not create port1_2\n"); + //Error=paInsufficientMemory; + } + //KPrintF("Calling DeletePort1\n"); + DeletePort(PortAudioStreamData->port1); + PortAudioStreamData->port1=NULL; + } + else + { + printf(" Could not create port1\n"); + //Error=paInsufficientMemory; + } + + // Error uebergeben? + //KPrintF("Calling ExitSubtask. stm=%lx\n",(ULONG)stm); + ExitSubTask(st,stm); + } +} + + +/* ##################################################################################################### */ + +PortAudioStream *GlobalPaStreamPtr=NULL; /* used for atexit(). Functions there have void parameter -> global Pointer needed */ + + +/* + Pa_StartStream() and Pa_StopStream() begin and terminate audio processing. + Pa_StopStream() waits until all pending audio buffers have been played. + Pa_AbortStream() stops playing immediately without waiting for pending + buffers to complete. + */ + +PaError Pa_StartStream_audev( PortAudioStream *stream ) +{ + int Error; + // KPrintF("%s() called\n",__FUNCTION__); + if(stream) + { + // printf(" %s called for Stream %u\n",__FUNCTION__,((PortAudioStreamStruct*)stream)->AF_StreamID); + ((PortAudioStreamStruct*)stream)->StreamActive=1; + SendSubTaskMsg(((PortAudioStreamStruct*)stream)->st,STC_START,NULL); + Error=paNoError; + } + else + { + // printf(" %s called with NULL-Ptr\n",__FUNCTION__); + Error=paBadStreamPtr; + + } + + return Error; +} + +/* ########################################################################## */ + + +//PaError Pa_StopStream( PortAudioStream *stream ); + +PaError Pa_AbortStream_audev( PortAudioStream *stream ) +{ + // KPrintF("%s() called\n",__FUNCTION__); + // printf(" %s called for Stream %u\n",__FUNCTION__,((PortAudioStreamStruct*)stream)->AF_StreamID); + ((PortAudioStreamStruct*)stream)->StreamActive=0; + return paNoError; +} + +/* ########################################################################## */ +/* + Pa_StreamActive() returns one when the stream is playing audio, + zero when not playing, or a negative error number if the + stream is invalid. + The stream is active between calls to Pa_StartStream() and Pa_StopStream(), + but may also become inactive if the callback returns a non-zero value. + In the latter case, the stream is considered inactive after the last + buffer has finished playing. + */ + + +PaError Pa_StreamActive_audev( PortAudioStream *stream ) +{ + // KPrintF("%s() called\n",__FUNCTION__); + + if(stream) + { + // printf(" %s called for Stream %u\n returning %u\n",__FUNCTION__,((PortAudioStreamStruct*)stream)->AF_StreamID,((PortAudioStreamStruct*)stream)->StreamActive); + + return ((PortAudioStreamStruct*)stream)->StreamActive; //paNoError; + } + else + { + // printf(" %s called with NULL-Ptr\n",__FUNCTION__); + // printf(" returning paBadStreamPtr\n"); + return paBadStreamPtr; // <0 is error + + } +} + +/* ########################################################################## */ +/* + Pa_OpenDefaultStream() is a simplified version of Pa_OpenStream() that + opens the default input and/or ouput devices. Most parameters have + identical meaning to their Pa_OpenStream() counterparts, with the following + exceptions: + + If either numInputChannels or numOutputChannels is 0 the respective device + is not opened (same as passing paNoDevice in the device arguments to Pa_OpenStream() ) + + sampleFormat applies to both the input and output buffers. + */ + + + +PaError Pa_OpenDefaultStream_audev( PortAudioStream** stream, + int numInputChannels, + int numOutputChannels, + PaSampleFormat sampleFormat, + double sampleRate, + unsigned long framesPerBuffer, + unsigned long numberOfBuffers, + PortAudioCallback *callback, + void *userData ) +{ + +// KPrintF("%s() called\n",__FUNCTION__); + // KPrintF("%s() called\n",__FUNCTION__); + /* + File=fopen("Samples","w"); + if(!File) + { + printf("Kann File nicht oeffnen\n"); + return paInternalError; + } + */ + + static unsigned int StreamNr=1; + PortAudioStreamStruct* StreamStruct; + int Error=paInternalError; + struct GfxBase *GfxBase; + unsigned int clock; + + // printf(" %s called\n",__FUNCTION__); + // printf(" numInputChannels=%d\n",numInputChannels); + // printf(" numOutputChannels=%d\n",numOutputChannels); + // printf(" sampleFormat=%lu (%u bytes)\n",sampleFormat,Pa_GetSampleSize_audev(sampleFormat)); + // printf(" sampleRate=%f\n",sampleRate); + // printf(" framesPerBuffer=%lu\n",framesPerBuffer); // a frame is numOutputChannels * BytesPerSample + // printf(" numberOfBuffers=%lu\n",numberOfBuffers); // this is only a suggestion how many buffers to use, e.g double buffering + // printf(" userData=$%p\n",userData); + + + GfxBase = (struct GfxBase *)OpenLibrary((CONST_STRPTR)"graphics.library",0L); + if (GfxBase) + { + if (GfxBase->DisplayFlags & PAL) + { + clock = 3546895; /* PAL clock */ + } + else + { + clock = 3579545; /* NTSC clock */ + } + CloseLibrary((struct Library *) GfxBase); + + StreamStruct=(PortAudioStreamStruct*)malloc(sizeof(PortAudioStreamStruct)); + if(StreamStruct) + { + memset(StreamStruct,0,sizeof(PortAudioStreamStruct)); /* initilize all entries */ + StreamStruct->device=1; /* device must be initialized to !=0 (for 0 is success) */ + + // printf(" Setting Stream to %u\n",StreamNr); + StreamStruct->AF_StreamID=StreamNr; + StreamNr++; + + StreamStruct->callback=callback; // store ptr to callback function + StreamStruct->framesPerBuffer=framesPerBuffer;//*global_bufsize_factor; // AF Test mit n mal 512 Byte Puffern + StreamStruct->numInputChannels=numInputChannels; + StreamStruct->numOutputChannels=numOutputChannels; + StreamStruct->sampleFormat=sampleFormat; + StreamStruct->sampleRate=sampleRate; + + StreamStruct->clock=clock; + + /*----------------------------------*/ + /* Calculate playback sampling rate */ + /*----------------------------------*/ + StreamStruct->speed = (ULONG) (clock / sampleRate); + + + // ######################################## + + *stream=StreamStruct; + + GlobalPaStreamPtr=StreamStruct; /* in case of CTRL-C atexit()-Functions are void so a global pointer is needed */ + + /* Allocate two Audio Buffers in ChipMem for Amiga-8Bit-Samples */ + StreamStruct->ChipMemBuf1=(BYTE*)AllocMem(StreamStruct->framesPerBuffer,MEMF_CHIP); + if(StreamStruct->ChipMemBuf1) + { + StreamStruct->ChipMemBuf2=(BYTE*)AllocMem(StreamStruct->framesPerBuffer,MEMF_CHIP); + if(StreamStruct->ChipMemBuf2) + { + /* Allocate two Audio Buffers in FastMem for Espeak-16Bit-Samples */ + StreamStruct->FastMemBuf1=(SHORT*)AllocMem(StreamStruct->framesPerBuffer*Pa_GetSampleSize_audev(StreamStruct->sampleFormat),MEMF_PUBLIC); + //KPrintF("Allocating %lu Bytes for FastMemBuf1, Ptr=$%08lx\n",(ULONG)StreamStruct->framesPerBuffer*Pa_GetSampleSize_audev(StreamStruct->sampleFormat),(ULONG)StreamStruct->FastMemBuf1); + if(StreamStruct->FastMemBuf1) + { + StreamStruct->FastMemBuf2=(SHORT*)AllocMem(StreamStruct->framesPerBuffer*Pa_GetSampleSize_audev(StreamStruct->sampleFormat),MEMF_PUBLIC); + if(StreamStruct->FastMemBuf2) + { + /* Allocate two audio IO Blocks */ + StreamStruct->AIOptr1=(struct IOAudio*)AllocMem(sizeof(struct IOAudio),MEMF_PUBLIC|MEMF_CLEAR); + if(StreamStruct->AIOptr1) + { + StreamStruct->AIOptr1_2=(struct IOAudio*)AllocMem(sizeof(struct IOAudio),MEMF_PUBLIC|MEMF_CLEAR); + if(StreamStruct->AIOptr1_2) + { + StreamStruct->AIOptr2=(struct IOAudio*)AllocMem(sizeof(struct IOAudio),MEMF_PUBLIC|MEMF_CLEAR); + if(StreamStruct->AIOptr2) + { + StreamStruct->AIOptr2_2=(struct IOAudio*)AllocMem(sizeof(struct IOAudio),MEMF_PUBLIC|MEMF_CLEAR); + if(StreamStruct->AIOptr2_2) + { + StreamStruct->AIOptrStartStop=(struct IOAudio*)AllocMem(sizeof(struct IOAudio),MEMF_PUBLIC|MEMF_CLEAR); + if(StreamStruct->AIOptrStartStop) + { + + StreamStruct->LP_FilterSate=getAudioFilterState(); // read current state of LP-Filter + setAudioFilterState(0); // turn Filter off + + + StreamStruct->st = SpawnSubTask("SamAudioTask",SamAudioTask,StreamStruct); + if (StreamStruct->st) + { + Error=paNoError; + return Error; + } + Error=paInternalError; + FreeMem(StreamStruct->AIOptr2,sizeof(struct IOAudio)); + StreamStruct->AIOptr2=NULL; + } + else + { + printf(" not enough memory for allocating AIOptrStartStop\n"); + Error=paInsufficientMemory; + } + FreeMem(StreamStruct->AIOptr2_2,sizeof(struct IOAudio)); + } + else + { + printf(" not enough memory for allocating AIOptr2_2\n"); + Error=paInsufficientMemory; + } + FreeMem(StreamStruct->AIOptr2,sizeof(struct IOAudio)); + StreamStruct->AIOptr2=NULL; + } + else + { + printf(" not enough memory for allocating AIOptr2\n"); + Error=paInsufficientMemory; + } + FreeMem(StreamStruct->AIOptr1_2,sizeof(struct IOAudio)); + StreamStruct->AIOptr1_2=NULL; + + } + else + { + printf(" not enough memory for allocating AIOptr1_2\n"); + Error=paInsufficientMemory; + } + FreeMem(StreamStruct->AIOptr1,sizeof(struct IOAudio)); + StreamStruct->AIOptr1=NULL; + } + else + { + printf(" not enough memory for allocating AIOptr1\n"); + Error=paInsufficientMemory; + } + FreeMem(StreamStruct->FastMemBuf2,StreamStruct->framesPerBuffer*Pa_GetSampleSize_audev(StreamStruct->sampleFormat)); + StreamStruct->FastMemBuf2=NULL; + } + else + { + printf(" Could not allocate FastMemBuf2 (%lu Bytes)\n",StreamStruct->framesPerBuffer*Pa_GetSampleSize_audev(StreamStruct->sampleFormat)); + Error=paInsufficientMemory; + } + FreeMem(StreamStruct->FastMemBuf1,StreamStruct->framesPerBuffer*Pa_GetSampleSize_audev(StreamStruct->sampleFormat)); + StreamStruct->FastMemBuf1=NULL; + } + else + { + printf(" Could not allocate FastMemBuf1 (%lu Bytes)\n",StreamStruct->framesPerBuffer*Pa_GetSampleSize_audev(StreamStruct->sampleFormat)); + Error=paInsufficientMemory; + } + FreeMem(StreamStruct->ChipMemBuf2,StreamStruct->framesPerBuffer); + StreamStruct->ChipMemBuf2=NULL; + } + else + { + printf(" Could not allocate ChipMemBuf2 (%lu Bytes)\n",StreamStruct->framesPerBuffer); + Error=paInsufficientMemory; + } + FreeMem(StreamStruct->ChipMemBuf1,StreamStruct->framesPerBuffer); + StreamStruct->ChipMemBuf1=NULL; + } + else + { + printf(" Could not allocate ChipMemBuf1 (%lu Bytes)\n",StreamStruct->framesPerBuffer); + Error=paInsufficientMemory; + } + + free(StreamStruct); + StreamStruct=NULL; + *stream=NULL; + GlobalPaStreamPtr=NULL; /* in case of CTRL-C atexit()-Functions are void so a global pointer is needed */ + + } + else + { + printf(" not enough memory for allocating stream %u\n",StreamNr); + Error=paInsufficientMemory; + } + + } + else + { + printf("Unable to open graphics.library\n"); + Error=paInternalError; + + } + // KPrintF("Finished %s\n",__FUNCTION__); + return Error; +} + + +/* ########################################################################## */ +/* + Pa_CloseStream() closes an audio stream, flushing any pending buffers. + */ + +PaError Pa_CloseStream_audev( PortAudioStream *stream ) +{ + //KPrintF("%s() called\n",__FUNCTION__); + + PortAudioStreamStruct *StreamStruct=(PortAudioStreamStruct*)stream; + + if(stream) + { + // printf(" %s called for Stream %u\n",__FUNCTION__,StreamStruct->AF_StreamID); + + if(StreamStruct->st) + { + KillSubTask(StreamStruct->st); + StreamStruct->st=NULL; + } + + if(StreamStruct->device==0) + { + CloseDevice((struct IORequest*)StreamStruct->AIOptr1); + StreamStruct->device=1; + } + + if(StreamStruct->portStartStop) + { + DeletePort(StreamStruct->portStartStop); + StreamStruct->portStartStop=0; + } + + if(StreamStruct->port2_2) + { + DeletePort(StreamStruct->port2_2); + StreamStruct->port2_2=0; + } + + + if(StreamStruct->port2) + { + DeletePort(StreamStruct->port2); + StreamStruct->port2=0; + } + + if(StreamStruct->port1_2) + { + DeletePort(StreamStruct->port1_2); + StreamStruct->port1_2=0; + } + + if(StreamStruct->port1) + { + DeletePort(StreamStruct->port1); + StreamStruct->port1=0; + } + + if(StreamStruct->AIOptrStartStop) + { + FreeMem(StreamStruct->AIOptrStartStop,sizeof(struct IOAudio)); + StreamStruct->AIOptrStartStop=NULL; + } + + if(StreamStruct->AIOptr2_2) + { + FreeMem(StreamStruct->AIOptr2_2,sizeof(struct IOAudio)); + StreamStruct->AIOptr2_2=NULL; + } + + if(StreamStruct->AIOptr2) + { + FreeMem(StreamStruct->AIOptr2,sizeof(struct IOAudio)); + StreamStruct->AIOptr2=NULL; + } + + if(StreamStruct->AIOptr1_2) + { + FreeMem(StreamStruct->AIOptr1_2,sizeof(struct IOAudio)); + StreamStruct->AIOptr1_2=NULL; + } + + if(StreamStruct->AIOptr1) + { + FreeMem(StreamStruct->AIOptr1,sizeof(struct IOAudio)); + StreamStruct->AIOptr1=NULL; + } + + if(StreamStruct->FastMemBuf2) + { + FreeMem(StreamStruct->FastMemBuf2,StreamStruct->framesPerBuffer*Pa_GetSampleSize_audev(StreamStruct->sampleFormat)); + StreamStruct->FastMemBuf2=NULL; + } + + if(StreamStruct->FastMemBuf1) + { + FreeMem(StreamStruct->FastMemBuf1,StreamStruct->framesPerBuffer*Pa_GetSampleSize_audev(StreamStruct->sampleFormat)); + StreamStruct->FastMemBuf1=NULL; + } + + + if(StreamStruct->ChipMemBuf2) + { + FreeMem(StreamStruct->ChipMemBuf2,StreamStruct->framesPerBuffer); + StreamStruct->ChipMemBuf2=NULL; + } + + if(StreamStruct->ChipMemBuf1) + { + FreeMem(StreamStruct->ChipMemBuf1,StreamStruct->framesPerBuffer); + StreamStruct->ChipMemBuf1=NULL; + } + + setAudioFilterState(StreamStruct->LP_FilterSate); // set last state of LP-Filter again + + free(StreamStruct); + GlobalPaStreamPtr=NULL; /* in case of CTRL-C atexit()-Functions are void so a global pointer is needed */ + + + // printf(" returning paNoError\n"); + return paNoError; + } + else + { + // printf(" %s called with NULL-Ptr\n",__FUNCTION__); + // printf(" returning paBadStreamPtr\n"); + return paBadStreamPtr; // <0 is error + + } +/* + if(File) + { + fclose(File); + File=NULL; + } +*/ +} + + +/* ########################################################################## */ +/* + Pa_Initialize() is the library initialisation function - call this before + using the library. + */ + + +PaError Pa_Initialize_audev( void ) +{ + int Error; + // printf(" %s called\n",__FUNCTION__); + // KPrintF("%s() called\n",__FUNCTION__); + + Error=paNoError; + + return Error; +} + + + +// ############################################################################## +// not needed by espeak but used by myself, AF 18.May2017 + +/* + Return size in bytes of a single sample in a given PaSampleFormat + or paSampleFormatNotSupported. + */ +PaError Pa_GetSampleSize_audev( PaSampleFormat format ) +{ + // KPrintF("%s() called\n",__FUNCTION__); + switch (format) + { + case paFloat32 : return 4; /*always available*/ + case paInt16 : return 2; /*always available*/ + case paInt32 : return 4; /*always available*/ + case paInt24 : return 6; + case paPackedInt24 : return 6; + case paInt8 : return 1; + case paUInt8 : return 1; /* unsigned 8 bit, 128 is "ground" */ + default : return paSampleFormatNotSupported; + } +} + + + + + +// ############################################################################## +/* reads 16Bit Signed Samples from Source and writes 8Bit Signed Smaples to Dest. */ +/* 16 Bit Samples must be BIG_ENDIAN */ +/* SampleCount Samples will be read */ +/* SampleCount must be multiple of 2 */ +/* Returns number of copied samples */ +/* AF, 15.76.2017 */ + +#ifdef HFHFHFHF +STATIC_FUNC UWORD Convert8USamples(SHORT *Source16S, BYTE *Dest8S, ULONG SampleCount) +{ + UWORD i=0; + ULONG *SourcePtr=(ULONG*)Source16S; /* we read 2 16Bit-Samples at once */ + USHORT *DestPtr=(USHORT*)Dest8S; /* we write 2 8Bit-Samples at once */ + ULONG SourceSamples; + USHORT DestSamples; + + if(SampleCount%2) + { + printf("%s() SampleCount %lu is not even!\n",__FUNCTION__,SampleCount); + /* we read probably one bad sample but continue anyway */ + } + + for(;i>16) | ((SourceSamples &0xff00) >> 8); /* extract the two High-Bytes */ + *DestPtr++=DestSamples; + + /*printf("SourceSamples=0x%0lx, DestSamples=0x%0hx\n",SourceSamples,DestSamples);*/ + } + return i*2; +} +#else +STATIC_FUNC UWORD Convert8USamples(UBYTE *Source8U, BYTE *Dest8S, ULONG SampleCount) +{ + unsigned long i; + for(i=0;i global Pointer needed */ +void Abort_Pa_CloseStream_audev (void) +{ + if(GlobalPaStreamPtr) + { + // KPrintF("%s() called with Stream=$%08lx\n",__FUNCTION__,GlobalPaStreamPtr); + Pa_CloseStream_audev(GlobalPaStreamPtr); + GlobalPaStreamPtr=NULL; + } + else + { + // KPrintF("%s() called but nothing to do\n",__FUNCTION__); + } +} + + + diff --git a/src/amiga/portaudio/portaudio_audev.h b/src/amiga/portaudio/portaudio_audev.h new file mode 100644 index 00000000..4efd64c6 --- /dev/null +++ b/src/amiga/portaudio/portaudio_audev.h @@ -0,0 +1,40 @@ +/*************************************************************************** + * Copyright (C) 2017 by Alexander Fritsch * + * email: selco@t-online.de * + ***************************************************************************/ +/* + * portaudio_audev.h + * + * Created on: Nov 28, 2017 + * Author: Alexander Fritsch + */ + +#ifndef SRC_AMIGA_PORTAUDIO_PORTAUDIO_AUDEV_H_ +#define SRC_AMIGA_PORTAUDIO_PORTAUDIO_AUDEV_H_ + +#include "../portaudio18.h" + +/* prototypes to be used in general portaudio.cpp only */ + +PaError Pa_StartStream_audev( PortAudioStream *stream ); +PaError Pa_AbortStream_audev( PortAudioStream *stream ); +PaError Pa_StreamActive_audev( PortAudioStream *stream ); +PaError Pa_OpenDefaultStream_audev( PortAudioStream** stream, + int numInputChannels, + int numOutputChannels, + PaSampleFormat sampleFormat, + double sampleRate, + unsigned long framesPerBuffer, + unsigned long numberOfBuffers, + PortAudioCallback *callback, + void *userData ); +PaError Pa_CloseStream_audev( PortAudioStream *stream ); +PaError Pa_Initialize_audev( void ); +PaError Pa_GetSampleSize_audev( PaSampleFormat format ); +void Abort_Pa_CloseStream_audev (void); + + + + + +#endif /* SRC_AMIGA_PORTAUDIO_PORTAUDIO_AUDEV_H_ */ diff --git a/src/amiga/portaudio/subtask_support.c b/src/amiga/portaudio/subtask_support.c new file mode 100644 index 00000000..d60188c9 --- /dev/null +++ b/src/amiga/portaudio/subtask_support.c @@ -0,0 +1,141 @@ +/**************************************************************/ +/* Functions for easy and secure spawning/killing of subtasks */ +/* taken from MUI subtask example - A.F. March 10th 2004 */ +/**************************************************************/ + +#include "subtask_support.h" +#include +//#include +#include +#include +#include +#include + +/* BEGIN -resident support for new task, suggested by bebbo 16.Dec1028 */ +// put the a4 reg into my task + +// get a4 helper +ULONG __get_a4() { + asm("move.l a4,d0"); +} + +// load a4 from my task +void __restore_a4() { + // do not use ExecBase via a4 yet + struct Library * SysBase = *(struct Library **)4; + struct Task * task = FindTask(0); + asm("\tmove.l %0,a4 ;\n" + : /* output */ + : "r" (task->tc_UserData) /* input */ + ); +} + +/* END -resident support for new task, suggested by bebbo 16.Dec1028 */ + + +LONG SendSubTaskMsg(struct SubTask *st,WORD command,APTR params) +{ + st->st_Message.stm_Message.mn_ReplyPort = st->st_Reply; + st->st_Message.stm_Message.mn_Length = sizeof(struct SubTaskMsg); + st->st_Message.stm_Command = command; + st->st_Message.stm_Parameter = params; + st->st_Message.stm_Result = 0; + + PutMsg(command==STC_STARTUP ? &((struct Process *)st->st_Task)->pr_MsgPort : st->st_Port,(struct Message *)&st->st_Message); + WaitPort(st->st_Reply); + GetMsg(st->st_Reply); + + return(st->st_Message.stm_Result); +} + + +struct SubTask *SpawnSubTask(char *name,VOID (*func)(VOID),APTR data) +{ + struct SubTask *st; + + st = (struct SubTask*) AllocVec(sizeof(struct SubTask),MEMF_PUBLIC|MEMF_CLEAR); + if (st) + { + st->st_Reply = CreateMsgPort(); + if (st->st_Reply) + { + st->st_Data = data; + st->st_Task = (struct Task *)CreateNewProcTags(NP_Entry,(unsigned long)func,NP_Name,(unsigned long)name, + NP_Input, __get_a4(), // abuse NP_Input to pass a4 -> will be put into pr_CIS + TAG_DONE); + if (st->st_Task) + { + + if (SendSubTaskMsg(st,STC_STARTUP,st)) + { + return(st); + } + } + DeleteMsgPort(st->st_Reply); + } + FreeVec(st); + } + return(NULL); +} + + +VOID KillSubTask(struct SubTask *st) +{ + SendSubTaskMsg(st,STC_SHUTDOWN,st); + DeleteMsgPort(st->st_Reply); + FreeVec(st); +} + +/* the following functions are called from the sub task */ + +VOID ExitSubTask(struct SubTask *st,struct SubTaskMsg *stm) +{ + /* + ** We reply after a Forbid() to make sure we're really gone + ** when the main task continues. + */ + + if (st->st_Port) + DeleteMsgPort(st->st_Port); + + Forbid(); + stm->stm_Result = FALSE; + ReplyMsg((struct Message *)stm); +} + +struct SubTask *InitSubTask(void) +{ + struct Task *me = FindTask(NULL); + struct SubTask *st; + struct SubTaskMsg *stm; + + /* + ** Wait for our startup message from the SpawnSubTask() function. + */ + + WaitPort(&((struct Process *)me)->pr_MsgPort); + stm = (struct SubTaskMsg *)GetMsg(&((struct Process *)me)->pr_MsgPort); + st = (struct SubTask *)stm->stm_Parameter; + + if ((st->st_Port = CreateMsgPort())) + { + /* + ** Reply startup message, everything ok. + ** Note that if the initialization fails, the code falls + ** through and replies the startup message with a stm_Result + ** of 0 after a Forbid(). This tells SpawnSubTask() that the + ** sub task failed to run. + */ + + stm->stm_Result = TRUE; + ReplyMsg((struct Message *)stm); + return(st); + } + else + { + ExitSubTask(st,stm); + return(NULL); + } +} + + diff --git a/src/amiga/portaudio/subtask_support.h b/src/amiga/portaudio/subtask_support.h new file mode 100644 index 00000000..97277561 --- /dev/null +++ b/src/amiga/portaudio/subtask_support.h @@ -0,0 +1,47 @@ +#ifndef __SUBTASK_SUPPORT_H__ + #define __SUBTASK_SUPPORT_H__ + +/**************************************************************/ +/* Functions for easy and secure spawning/killing of subtasks */ +/* taken from MUI subtask example - A.F. March 10th 2004 */ +/**************************************************************/ + + +#include + +struct SubTaskMsg +{ + struct Message stm_Message; + WORD stm_Command; + APTR stm_Parameter; + LONG stm_Result; +}; + +struct SubTask +{ + struct Task *st_Task; /* sub task pointer */ + struct MsgPort *st_Port; /* allocated by sub task */ + struct MsgPort *st_Reply; /* allocated by main task */ + APTR st_Data; /* more initial data to pass to the sub task */ + struct SubTaskMsg st_Message; /* Message buffer */ +}; + + +#define STC_START 0 +#define STC_STOP 1 +#define STC_STARTUP -2 +#define STC_SHUTDOWN -1 + + + +LONG SendSubTaskMsg(struct SubTask *st,WORD command,APTR params); +struct SubTask *SpawnSubTask(char *name,VOID (*func)(VOID),APTR data); +VOID KillSubTask(struct SubTask *st); + +/* the following functions are called from the sub task */ +VOID ExitSubTask(struct SubTask *st,struct SubTaskMsg *stm); +struct SubTask *InitSubTask(void); + + + +#endif diff --git a/src/amiga/portaudio18.h b/src/amiga/portaudio18.h new file mode 100644 index 00000000..2ab8e02a --- /dev/null +++ b/src/amiga/portaudio18.h @@ -0,0 +1,466 @@ +// NOTE: Copy this file to portaudio.h in order to compile with V18 portaudio + + +#ifndef PORT_AUDIO_H +#define PORT_AUDIO_H + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/* + * $Id: portaudio.h,v 1.5 2002/03/26 18:04:22 philburk Exp $ + * PortAudio Portable Real-Time Audio Library + * PortAudio API Header File + * Latest version available at: http://www.audiomulch.com/portaudio/ + * + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +typedef int PaError; +typedef enum { + paNoError = 0, + + paHostError = -10000, + paInvalidChannelCount, + paInvalidSampleRate, + paInvalidDeviceId, + paInvalidFlag, + paSampleFormatNotSupported, + paBadIODeviceCombination, + paInsufficientMemory, + paBufferTooBig, + paBufferTooSmall, + paNullCallback, + paBadStreamPtr, + paTimedOut, + paInternalError, + paDeviceUnavailable +} PaErrorNum; + +/* + Pa_Initialize() is the library initialisation function - call this before + using the library. + +*/ + +PaError Pa_Initialize( void ); + +/* + Pa_Terminate() is the library termination function - call this after + using the library. + +*/ + +PaError Pa_Terminate( void ); + +/* + Pa_GetHostError() returns a host specific error code. + This can be called after receiving a PortAudio error code of paHostError. + +*/ + +long Pa_GetHostError( void ); + +/* + Pa_GetErrorText() translates the supplied PortAudio error number + into a human readable message. + +*/ + +const char *Pa_GetErrorText( PaError errnum ); + +/* + Sample formats + + These are formats used to pass sound data between the callback and the + stream. Each device has a "native" format which may be used when optimum + efficiency or control over conversion is required. + + Formats marked "always available" are supported (emulated) by all + PortAudio implementations. + + The floating point representation (paFloat32) uses +1.0 and -1.0 as the + maximum and minimum respectively. + + paUInt8 is an unsigned 8 bit format where 128 is considered "ground" + +*/ + +typedef unsigned long PaSampleFormat; +#define paFloat32 ((PaSampleFormat) (1<<0)) /*always available*/ +#define paInt16 ((PaSampleFormat) (1<<1)) /*always available*/ +#define paInt32 ((PaSampleFormat) (1<<2)) /*always available*/ +#define paInt24 ((PaSampleFormat) (1<<3)) +#define paPackedInt24 ((PaSampleFormat) (1<<4)) +#define paInt8 ((PaSampleFormat) (1<<5)) +#define paUInt8 ((PaSampleFormat) (1<<6)) +#define paCustomFormat ((PaSampleFormat) (1<<16)) + +/* + Device enumeration mechanism. + + Device ids range from 0 to Pa_CountDevices()-1. + + Devices may support input, output or both. + +*/ + +typedef int PaDeviceID; +#define paNoDevice -1 + +int Pa_CountDevices( void ); + +typedef struct +{ + int structVersion; + const char *name; + int maxInputChannels; + int maxOutputChannels; + /* Number of discrete rates, or -1 if range supported. */ + int numSampleRates; + /* Array of supported sample rates, or {min,max} if range supported. */ + const double *sampleRates; + PaSampleFormat nativeSampleFormats; +} +PaDeviceInfo; + +/* + Pa_GetDefaultInputDeviceID(), Pa_GetDefaultOutputDeviceID() return the + default device ids for input and output respectively, or paNoDevice if + no device is available. + The result can be passed to Pa_OpenStream(). + + On the PC, the user can specify a default device by + setting an environment variable. For example, to use device #1. + + set PA_RECOMMENDED_OUTPUT_DEVICE=1 + + The user should first determine the available device ids by using + the supplied application "pa_devs". + +*/ + +PaDeviceID Pa_GetDefaultInputDeviceID( void ); +PaDeviceID Pa_GetDefaultOutputDeviceID( void ); + + + +/* + Pa_GetDeviceInfo() returns a pointer to an immutable PaDeviceInfo structure + for the device specified. + If the device parameter is out of range the function returns NULL. + + PortAudio manages the memory referenced by the returned pointer, the client + must not manipulate or free the memory. The pointer is only guaranteed to be + valid between calls to Pa_Initialize() and Pa_Terminate(). + +*/ + +const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID device ); + +/* + PaTimestamp is used to represent a continuous sample clock with arbitrary + start time that can be used for syncronization. The type is used for the + outTime argument to the PortAudioCallback and as the result of Pa_StreamTime() + +*/ + +typedef double PaTimestamp; + +/* + PortAudioCallback is implemented by PortAudio clients. + + inputBuffer and outputBuffer are arrays of interleaved samples, + the format, packing and number of channels used by the buffers are + determined by parameters to Pa_OpenStream() (see below). + + framesPerBuffer is the number of sample frames to be processed by the callback. + + outTime is the time in samples when the buffer(s) processed by + this callback will begin being played at the audio output. + See also Pa_StreamTime() + + userData is the value of a user supplied pointer passed to Pa_OpenStream() + intended for storing synthesis data etc. + + return value: + The callback can return a non-zero value to stop the stream. This may be + useful in applications such as soundfile players where a specific duration + of output is required. However, it is not necessary to utilise this mechanism + as StopStream() will also terminate the stream. A callback returning a + non-zero value must fill the entire outputBuffer. + + NOTE: None of the other stream functions may be called from within the + callback function except for Pa_GetCPULoad(). + +*/ + +typedef int (PortAudioCallback)( + void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ); + + +/* + Stream flags + + These flags may be supplied (ored together) in the streamFlags argument to + the Pa_OpenStream() function. + +*/ + +#define paNoFlag (0) +#define paClipOff (1<<0) /* disable default clipping of out of range samples */ +#define paDitherOff (1<<1) /* disable default dithering */ +#define paPlatformSpecificFlags (0x00010000) +typedef unsigned long PaStreamFlags; + +/* + A single PortAudioStream provides multiple channels of real-time + input and output audio streaming to a client application. + Pointers to PortAudioStream objects are passed between PortAudio functions. +*/ + +typedef void PortAudioStream; +#define PaStream PortAudioStream + +/* + Pa_OpenStream() opens a stream for either input, output or both. + + stream is the address of a PortAudioStream pointer which will receive + a pointer to the newly opened stream. + + inputDevice is the id of the device used for input (see PaDeviceID above.) + inputDevice may be paNoDevice to indicate that an input device is not required. + + numInputChannels is the number of channels of sound to be delivered to the + callback. It can range from 1 to the value of maxInputChannels in the + PaDeviceInfo record for the device specified by the inputDevice parameter. + If inputDevice is paNoDevice numInputChannels is ignored. + + inputSampleFormat is the sample format of inputBuffer provided to the callback + function. inputSampleFormat may be any of the formats described by the + PaSampleFormat enumeration (see above). PortAudio guarantees support for + the device's native formats (nativeSampleFormats in the device info record) + and additionally 16 and 32 bit integer and 32 bit floating point formats. + Support for other formats is implementation defined. + + inputDriverInfo is a pointer to an optional driver specific data structure + containing additional information for device setup or stream processing. + inputDriverInfo is never required for correct operation. If not used + inputDriverInfo should be NULL. + + outputDevice is the id of the device used for output (see PaDeviceID above.) + outputDevice may be paNoDevice to indicate that an output device is not required. + + numOutputChannels is the number of channels of sound to be supplied by the + callback. See the definition of numInputChannels above for more details. + + outputSampleFormat is the sample format of the outputBuffer filled by the + callback function. See the definition of inputSampleFormat above for more + details. + + outputDriverInfo is a pointer to an optional driver specific data structure + containing additional information for device setup or stream processing. + outputDriverInfo is never required for correct operation. If not used + outputDriverInfo should be NULL. + + sampleRate is the desired sampleRate. For full-duplex streams it is the + sample rate for both input and output + + framesPerBuffer is the length in sample frames of all internal sample buffers + used for communication with platform specific audio routines. Wherever + possible this corresponds to the framesPerBuffer parameter passed to the + callback function. + + numberOfBuffers is the number of buffers used for multibuffered communication + with the platform specific audio routines. If you pass zero, then an optimum + value will be chosen for you internally. This parameter is provided only + as a guide - and does not imply that an implementation must use multibuffered + i/o when reliable double buffering is available (such as SndPlayDoubleBuffer() + on the Macintosh.) + + streamFlags may contain a combination of flags ORed together. + These flags modify the behaviour of the streaming process. Some flags may only + be relevant to certain buffer formats. + + callback is a pointer to a client supplied function that is responsible + for processing and filling input and output buffers (see above for details.) + + userData is a client supplied pointer which is passed to the callback + function. It could for example, contain a pointer to instance data necessary + for processing the audio buffers. + + return value: + Upon success Pa_OpenStream() returns PaNoError and places a pointer to a + valid PortAudioStream in the stream argument. The stream is inactive (stopped). + If a call to Pa_OpenStream() fails a non-zero error code is returned (see + PaError above) and the value of stream is invalid. + +*/ + +PaError Pa_OpenStream( PortAudioStream** stream, + PaDeviceID inputDevice, + int numInputChannels, + PaSampleFormat inputSampleFormat, + void *inputDriverInfo, + PaDeviceID outputDevice, + int numOutputChannels, + PaSampleFormat outputSampleFormat, + void *outputDriverInfo, + double sampleRate, + unsigned long framesPerBuffer, + unsigned long numberOfBuffers, + PaStreamFlags streamFlags, + PortAudioCallback *callback, + void *userData ); + + +/* + Pa_OpenDefaultStream() is a simplified version of Pa_OpenStream() that opens + the default input and/or output devices. Most parameters have identical meaning + to their Pa_OpenStream() counterparts, with the following exceptions: + + If either numInputChannels or numOutputChannels is 0 the respective device + is not opened. This has the same effect as passing paNoDevice in the device + arguments to Pa_OpenStream(). + + sampleFormat applies to both the input and output buffers. + +*/ + +PaError Pa_OpenDefaultStream( PortAudioStream** stream, + int numInputChannels, + int numOutputChannels, + PaSampleFormat sampleFormat, + double sampleRate, + unsigned long framesPerBuffer, + unsigned long numberOfBuffers, + PortAudioCallback *callback, + void *userData ); + +/* + Pa_CloseStream() closes an audio stream, flushing any pending buffers. + +*/ + +PaError Pa_CloseStream( PortAudioStream* ); + +/* + Pa_StartStream() and Pa_StopStream() begin and terminate audio processing. + Pa_StopStream() waits until all pending audio buffers have been played. + Pa_AbortStream() stops playing immediately without waiting for pending + buffers to complete. + +*/ + +PaError Pa_StartStream( PortAudioStream *stream ); + +PaError Pa_StopStream( PortAudioStream *stream ); + +PaError Pa_AbortStream( PortAudioStream *stream ); + +/* + Pa_StreamActive() returns one (1) when the stream is active (ie playing + or recording audio), zero (0) when not playing, or a negative error number + if the stream is invalid. + The stream is active between calls to Pa_StartStream() and Pa_StopStream(), + but may also become inactive if the callback returns a non-zero value. + In the latter case, the stream is considered inactive after the last + buffer has finished playing. + +*/ + +PaError Pa_StreamActive( PortAudioStream *stream ); + +/* + Pa_StreamTime() returns the current output time in samples for the stream. + This time may be used as a time reference (for example synchronizing audio to + MIDI). + +*/ + +PaTimestamp Pa_StreamTime( PortAudioStream *stream ); + +/* + Pa_GetCPULoad() returns the CPU Load for the stream. + The "CPU Load" is a fraction of total CPU time consumed by the stream's + audio processing routines including, but not limited to the client supplied + callback. + A value of 0.5 would imply that PortAudio and the sound generating + callback was consuming roughly 50% of the available CPU time. + This function may be called from the callback function or the application. + +*/ + +double Pa_GetCPULoad( PortAudioStream* stream ); + +/* + Pa_GetMinNumBuffers() returns the minimum number of buffers required by + the current host based on minimum latency. + On the PC, for the DirectSound implementation, latency can be optionally set + by user by setting an environment variable. + For example, to set latency to 200 msec, put: + + set PA_MIN_LATENCY_MSEC=200 + + in the AUTOEXEC.BAT file and reboot. + If the environment variable is not set, then the latency will be determined + based on the OS. Windows NT has higher latency than Win95. + +*/ + +int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate ); + +/* + Pa_Sleep() puts the caller to sleep for at least 'msec' milliseconds. + You may sleep longer than the requested time so don't rely on this for + accurate musical timing. + + Pa_Sleep() is provided as a convenience for authors of portable code (such as + the tests and examples in the PortAudio distribution.) + +*/ + +void Pa_Sleep( long msec ); + +/* + Pa_GetSampleSize() returns the size in bytes of a single sample in the + supplied PaSampleFormat, or paSampleFormatNotSupported if the format is + no supported. + +*/ + +PaError Pa_GetSampleSize( PaSampleFormat format ); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* PORT_AUDIO_H */ diff --git a/src/amiga/sdlwrapper.c b/src/amiga/sdlwrapper.c new file mode 100644 index 00000000..678f009c --- /dev/null +++ b/src/amiga/sdlwrapper.c @@ -0,0 +1,144 @@ +/* AF, GWD, Nov,21 2018 */ +/* wraps certain SDL-Calls to my portaudio implementation */ + +/* leftovers from portaudio... */ +unsigned int global_benchmark_flag=0; +char *global_ProgramName="sam_globaler_name"; +unsigned int global_bufsize_factor=1; + +/************************************************************** */ +#include +#include + +#include "portaudio18.h" + +LONG KPrintF(STRPTR format, ...); +void Abort_Pa_CloseStream_audev (void); + +static PortAudioStream *pa_stream=NULL; + + +/************************************************************** */ + + +void SDL_CloseAudio(void) +{ +// KPrintF("%s()\n",__FUNCTION__); + Pa_CloseStream(pa_stream); +} +/************************************************************** */ + +void SDL_Delay(Uint32 ms) +{ +// KPrintF("%s(%ld)\n",__FUNCTION__,ms); + __chkabort(); + usleep(ms*1000); +} +/************************************************************** */ + + +char *SDL_Error_String="SDL Dummy_Error"; + +DECLSPEC char * SDL_GetError(void) +{ +// KPrintF("%s()\n",__FUNCTION__); + return SDL_Error_String; +} +/************************************************************** */ + +//flags=SDL_INIT_AUDIO The file I/O and threading subsystems are initialized +int SDL_Init(Uint32 flags) +{ +// KPrintF("%s(0x%lx)\n",__FUNCTION__,flags); + if(flags & SDL_INIT_AUDIO) + { + return Pa_Initialize(); + } + else + { + return paNoError; + } +} +/************************************************************** */ + +void (SDLCALL *SDL_CallbackFunction)(void *userdata, Uint8 *stream, int len); + +int PortAudioCallbackFunction( + void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime, void *userData ) +{ +//KPrintF("*****************%s(%ld)*********************\n",__FUNCTION__,framesPerBuffer); + SDL_CallbackFunction(userData, outputBuffer,framesPerBuffer); + return 0; /* continue until somebody Aborts the stream */ +} + + +int SDL_OpenAudio(SDL_AudioSpec* desired, SDL_AudioSpec* obtained) +{ + PaError Error; + PaSampleFormat SampleFormat; + +// KPrintF("%s()\n",__FUNCTION__); +// KPrintF("channels %ld\n",desired->channels); +// KPrintF("format %ld\n",desired->format); +// KPrintF("freq %ld\n",desired->freq); +// KPrintF("Padding %ld\n",desired->padding); +// KPrintF("Samples %ld\n",desired->samples); +// KPrintF("Silence %ld\n",desired->silence); +// KPrintF("Size %ld\n",desired->size); + + if(desired->format!=AUDIO_U8) + { + printf("Error: only SDL-Format AUDIO_U8 supported\n"); + return paSampleFormatNotSupported; // < 0 means error + } + else + { + SampleFormat=paUInt8; + } + + SDL_CallbackFunction=desired->callback; + + + Error=Pa_OpenDefaultStream( &pa_stream, + 0, /*int numInputChannels*/ + desired->channels, + SampleFormat, + desired->freq, + desired->samples, /* unsigned long framesPerBuffer*/ + 2, /*unsigned long numberOfBuffers*/ + PortAudioCallbackFunction, /* PortAudioCallback *callback */ + desired->userdata /* void *userData*/ ); + + if(obtained) + { + *obtained=*desired; + } + + return Error; +} +/************************************************************** */ + +// 1=audio callback is stopped when this returns. 0=start ausio callback +void SDL_PauseAudio(int pause_on) +{ +// KPrintF("%s(%ld)\n",__FUNCTION__,pause_on); + + if(0==pause_on) + { + Pa_StartStream(pa_stream); + } + else + { + Pa_AbortStream(pa_stream); + } + +} +/************************************************************** */ + +void SDL_Quit(void) // useful with atexit() +{ +// KPrintF("%s()\n",__FUNCTION__); + Abort_Pa_CloseStream(); +} diff --git a/src/amiga/stopwatch/stopwatch.c b/src/amiga/stopwatch/stopwatch.c new file mode 100644 index 00000000..30a1184e --- /dev/null +++ b/src/amiga/stopwatch/stopwatch.c @@ -0,0 +1,161 @@ +/*************************************************************************** + * Copyright (C) 2018 by Alexander Fritsch * + * email: selco@t-online.de * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write see: * + * . * + ***************************************************************************/ + +#include +#include +#include "stopwatch.h" +#include +#include + +struct StopWatch *AllocStopWatch(void) +{ + struct StopWatch *sw; + + sw=malloc(sizeof(struct StopWatch)); + if(sw) + { + ResetStopWatch(sw); + sw->OpenDevRetVal=1; + + sw->OpenDevRetVal=OpenDevice((CONST_STRPTR)TIMERNAME, UNIT_MICROHZ, &sw->timereq, 0); + if(0==sw->OpenDevRetVal) + { + sw->TimerBase = (struct TimeBase*)sw->timereq.io_Device; + return sw; + } + else + { + printf("%s(): OpenDevice(%s) failed.\n",__FUNCTION__,TIMERNAME); + } + free(sw); + sw=NULL; + } + else + { + printf("%s(): malloc failed.\n",__FUNCTION__); + } + return sw; +} + +void FreeStopWatch(struct StopWatch *sw) +{ + if(!sw) + { + printf("%s(): NULL-Pointer",__FUNCTION__); + return; + } + if(sw->OpenDevRetVal==0) + { + CloseDevice(&sw->timereq); + } + free(sw); +} + + +void StartStopWatch(struct StopWatch *sw) +{ + if(0==sw->running) + { + struct TimeBase *TimerBase=sw->TimerBase; /* GetSysTime and SubTime need a valid variable TimerBase */ + GetSysTime(&sw->StartTime); + sw->running=1; + } + else + { + printf("%s(): already running\n"); + } +} + +void StopStopWatch(struct StopWatch *sw) +{ + if(1==sw->running) + { + struct TimeBase *TimerBase=sw->TimerBase; /* GetSysTime and SubTime need a valid variable TimerBase */ + GetSysTime(&sw->StopTime); + SubTime(&sw->StopTime, &sw->StartTime); + + AddTime(&sw->TotalTime,&sw->StopTime); + sw->running=0; + } + else + { + printf("%S(): already stopped\n",__FUNCTION__); + } +} + +unsigned long StopWatchGetMilliSeconds(struct StopWatch *sw) +{ + if(0==sw->running) + { + return (sw->StopTime.tv_secs * 1000 + sw->StopTime.tv_micro / 1000); + } + else + { + printf("%s(): currently running\n"); + return 0; + } +} + +unsigned long StopWatchGetTotalMilliSeconds(struct StopWatch *sw) +{ + if(0==sw->running) + { + return (sw->TotalTime.tv_secs * 1000 + sw->TotalTime.tv_micro / 1000); + } + else + { + printf("%s(): currently running\n"); + return 0; + } +} + +unsigned long long StopWatchGetMicroSeconds(struct StopWatch *sw) +{ + if(0==sw->running) + { + return (sw->StopTime.tv_secs * 1000000 + sw->StopTime.tv_micro); + } + else + { + printf("%s(): currently running\n"); + return 0; + } +} + +unsigned long long StopWatchGetTotalMicroSeconds(struct StopWatch *sw) +{ + if(0==sw->running) + { + return (sw->TotalTime.tv_secs * 1000000 + sw->TotalTime.tv_micro); + } + else + { + printf("%s(): currently running\n"); + return 0; + } +} + + +void ResetStopWatch(struct StopWatch *sw) +{ + memset(&sw->StartTime,0,sizeof(sw->StartTime)); + memset(&sw->StopTime,0,sizeof(sw->StopTime)); + memset(&sw->TotalTime,0,sizeof(sw->TotalTime)); + sw->running=0; +} diff --git a/src/amiga/stopwatch/stopwatch.h b/src/amiga/stopwatch/stopwatch.h new file mode 100644 index 00000000..d06fbc23 --- /dev/null +++ b/src/amiga/stopwatch/stopwatch.h @@ -0,0 +1,43 @@ +/*************************************************************************** + * Copyright (C) 2018 by Alexander Fritsch * + * email: selco@t-online.de * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write see: * + * . * + ***************************************************************************/ + +#include +#include + +struct StopWatch +{ + struct timeval StartTime; /* start of current measurement */ + struct timeval StopTime; /* end of current measurement */ + struct timeval TotalTime; /* sum of all measurements */ + struct TimeBase *TimerBase; /* Device Base */ + struct IORequest timereq; /* IORequest */ + unsigned int OpenDevRetVal; /* Flag is OpenDevice was successful (0=success) */ + unsigned int running; /* Flag if th stopwatch is running */ +}; + +struct StopWatch *AllocStopWatch(void); +void FreeStopWatch(struct StopWatch *sw); +void StartStopWatch(struct StopWatch *sw); +void StopStopWatch(struct StopWatch *sw); +void ResetStopWatch(struct StopWatch *sw); +unsigned long StopWatchGetMilliSeconds(struct StopWatch *sw); +unsigned long long StopWatchGetMicroSeconds(struct StopWatch *sw); +unsigned long StopWatchGetTotalMilliSeconds(struct StopWatch *sw); +unsigned long long StopWatchGetTotalMicroSeconds(struct StopWatch *sw); + diff --git a/src/amiga/stopwatch/stopwatch_test.c b/src/amiga/stopwatch/stopwatch_test.c new file mode 100644 index 00000000..49999de8 --- /dev/null +++ b/src/amiga/stopwatch/stopwatch_test.c @@ -0,0 +1,68 @@ +/*************************************************************************** + * Copyright (C) 2018 by Alexander Fritsch * + * email: selco@t-online.de * +***************************************************************************/ +/* + * copmile with +/home/osboxes/opt/m68k-amigaos_26Nov18/bin/m68k-amigaos-gcc stopwatch_test.c stopwatch.c -O0 -Wall -noixemul -o test && sync +*/ + +#include "stopwatch.h" +#include +#include + + +struct StopWatch *sw1=NULL; +struct StopWatch *sw2=NULL; + +void CleanUp(void) +{ + if(sw2) + { + FreeStopWatch(sw2); + sw2=NULL; + } + if(sw1) + { + FreeStopWatch(sw1); + sw1=NULL; + } +} + +int main(void) +{ + sw1=AllocStopWatch(); + if(NULL==sw1) + { + printf("InitStopWatch 1 failed\n"); + CleanUp(); + return 1; + } + + sw2=AllocStopWatch(); + if(NULL==sw2) + { + printf("InitStopWatch 2 failed\n"); + CleanUp(); + return 2; + } + + + printf("Waiting 1 second for StopWatch 1...\n"); + StartStopWatch(sw1); + usleep(1000000); + StopStopWatch(sw1); + printf("StopWatch 1: %ldms elapsed\n",StopWatchGetMilliSeconds(sw1)); + printf("StopWatch 1: %lldus elapsed\n",StopWatchGetMicroSeconds(sw1)); + + printf("Waiting 2 more seconds for StopWatch 1...\n"); + StartStopWatch(sw1); + usleep(2000000); + StopStopWatch(sw1); + printf("StopWatch 1: %ldms elapsed\n",StopWatchGetMilliSeconds(sw1)); + printf("StopWatch 1: %lldus elapsed\n",StopWatchGetMicroSeconds(sw1)); + + printf("%ldms in total elapsed\n",StopWatchGetTotalMilliSeconds(sw1)); + + CleanUp(); +} diff --git a/src/amiga/version/amiga_version.c b/src/amiga/version/amiga_version.c new file mode 100644 index 00000000..6df552dc --- /dev/null +++ b/src/amiga/version/amiga_version.c @@ -0,0 +1,54 @@ +/*************************************************************************** + * Copyright (C) 2018 by Alexander Fritsch * + * email: selco@t-online.de * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write see: * + * . * + ***************************************************************************/ + +#ifdef mc68060 +#define __CPU__ "mc68060" +#elif defined mc68040 +#define __CPU__ "mc68040" +#elif defined mc68030 +#define __CPU__ "mc68030" +#elif defined mc68020 +#define __CPU__ "mc68020" +#elif defined mc68000 +#define __CPU__ "mc68000" +#else +#define __CPU__ "???????" +#endif + +#ifdef __HAVE_68881__ +#define __FPU__ "+mc68881" +#else +#define __FPU__ "" +#endif + + + +#define VERSION "1" +#define REVISION "2" /* Revision always starts with 1 ! */ +//#define DATE "15.07.2017" /* comes from make-command line as CXXFLAGS+=-DDATE=\\\"$(date +'%d.%m.%Y')\\\" */ +#define PROGNAME "sam" +#define COMMENT "BETA-Version, Alexander Fritsch, selco, based on SAM C-conversion by Sebastian Macke" +//#define COMMENT "Alexander Fritsch, selco, based on SAM C-conversion by Sebastian Macke" + +#define VERS PROGNAME" " VERSION "." REVISION +#define VERSTAG "\0$VER: " PROGNAME " " VERSION "." REVISION " (" DATE ") " COMMENT //", compiled for " __CPU__ __FPU__ + +char versiontag[] = VERSTAG; + +char toolchain_ver[] = "\0$TOOLCHAIN_VER: " TOOLCHAIN_VER; /* This macro comes from Makefile.amiga and contains git hash */ diff --git a/src/debug.c b/src/debug.c index 86e57977..d663ab17 100755 --- a/src/debug.c +++ b/src/debug.c @@ -1,7 +1,7 @@ #include -extern unsigned char signInputTable1[]; -extern unsigned char signInputTable2[]; +extern const unsigned char signInputTable1[]; +extern const unsigned char signInputTable2[]; void PrintPhonemes(unsigned char *phonemeindex, unsigned char *phonemeLength, unsigned char *stress) { diff --git a/src/endian.c b/src/endian.c new file mode 100644 index 00000000..24a8ecc9 --- /dev/null +++ b/src/endian.c @@ -0,0 +1,45 @@ + + +unsigned short swaps( unsigned short val) +{ + return ((val & 0xff) << 8) | ((val & 0xff00) >> 8); +} + +/* host to little endian */ + +#if PLATFORM_IS_BIG_ENDIAN + +unsigned short htoles( unsigned short val) +{ + /* need to swap bytes on a big endian platform */ + return swaps( val); +} +unsigned int htolew( unsigned int val) +{ + + /* need to swap bytes and words on a big endian platform */ + int RetVal; + ((unsigned char *)&RetVal)[0]=((unsigned char *)&val)[3]; + ((unsigned char *)&RetVal)[1]=((unsigned char *)&val)[2]; + ((unsigned char *)&RetVal)[2]=((unsigned char *)&val)[1]; + ((unsigned char *)&RetVal)[3]=((unsigned char *)&val)[0]; + + return RetVal; +} + + +#else + +unsigned short htoles( unsigned short val) +{ + /* no-op on a little endian platform */ + return val; +} + +unsigned int htolew( unsigned int val) +{ + /* no-op on a little endian platform */ + return val; +} + +#endif diff --git a/src/endian.h b/src/endian.h new file mode 100644 index 00000000..a38c0f02 --- /dev/null +++ b/src/endian.h @@ -0,0 +1,8 @@ + +/* + * AF, 20.Nov.2018 + * convert host to little endian short + * found at https://stackoverflow.com/questions/1873352/how-do-i-convert-a-value-from-host-byte-order-to-little-endian + */ +unsigned short htoles( unsigned short val); /* hotToLittleEndian Short */ +unsigned int htolew( unsigned int val); /* hotToLittleEndian Word */ diff --git a/src/main.c b/src/main.c index 966bc9f8..9955803b 100644 --- a/src/main.c +++ b/src/main.c @@ -12,35 +12,79 @@ #include #endif +#include "endian.h" // AF, Endian + +#include // AF, Test +#ifdef __AMIGA__ // AF, use ahi.device instead of audio.device + void set_ahi_devide(unsigned int unit); + void SetCpuSpecificFunctions(void); // AF, we compile some functions for 68000 and for 68020 + // AF STOPWATCH + #include "amiga/stopwatch/stopwatch.h" + struct StopWatch *sw_main=NULL; + + + #define ALLOCSTOPWATCH(x) \ + x=AllocStopWatch(); \ + if(NULL==x) \ + { \ + printf("InitStopWatch 1 failed\n"); \ + CleanUp(); \ + return 1; \ + } + + + #define CLEANUP_SW(x) {if(x) { FreeStopWatch(x); x=NULL; }} + void CleanUp(void) + { + CLEANUP_SW(sw_main); + } + + #endif + + + +#ifdef DEBUG + #define D(x) x + #define CLEANUP_SW(x) {if(x) { FreeStopWatch(x); x=NULL; }} +#else + // for debug-prints. Can be activated with -DDEBUG in Makefile + #define D(x) + #define CLEANUP_SW(x) + +#endif + + void WriteWav(char* filename, char* buffer, int bufferlength) { FILE *file = fopen(filename, "wb"); + unsigned int le_bufferlength; // AF, Endian if (file == NULL) return; //RIFF header fwrite("RIFF", 4, 1,file); - unsigned int filesize=bufferlength + 12 + 16 + 8 - 8; + unsigned int filesize=htolew(bufferlength + 12 + 16 + 8 - 8); // AF, Endian fwrite(&filesize, 4, 1, file); fwrite("WAVE", 4, 1, file); //format chunk fwrite("fmt ", 4, 1, file); - unsigned int fmtlength = 16; + unsigned int fmtlength = htolew(16); // AF, Endian fwrite(&fmtlength, 4, 1, file); - unsigned short int format=1; //PCM + unsigned short int format=htoles(1); //PCM // AF, Endian fwrite(&format, 2, 1, file); - unsigned short int channels=1; + unsigned short int channels=htoles(1); // AF, Endian fwrite(&channels, 2, 1, file); - unsigned int samplerate = 22050; + unsigned int samplerate = htolew(22050); // AF, Endian fwrite(&samplerate, 4, 1, file); fwrite(&samplerate, 4, 1, file); // bytes/second - unsigned short int blockalign = 1; + unsigned short int blockalign = htoles(1); // AF, Endian fwrite(&blockalign, 2, 1, file); - unsigned short int bitspersample=8; + unsigned short int bitspersample=htoles(8); // AF, Endian fwrite(&bitspersample, 2, 1, file); //data chunk fwrite("data", 4, 1, file); - fwrite(&bufferlength, 4, 1, file); + le_bufferlength=htolew(bufferlength); // AF, Endian + fwrite(&le_bufferlength, 4, 1, file); fwrite(buffer, bufferlength, 1, file); fclose(file); @@ -58,6 +102,9 @@ void PrintUsage() printf(" -wav filename output to wav instead of libsdl\n"); printf(" -sing special treatment of pitch\n"); printf(" -debug print additional debug messages\n"); +#ifdef __AMIGA__ + printf(" -ahi unit use Amiga AHI-device\n"); +#endif printf("\n"); @@ -100,6 +147,7 @@ void MixAudio(void *unused, Uint8 *stream, int len) int bufferpos = GetBufferLength(); char *buffer = GetBuffer(); int i; + if (pos >= bufferpos) return; if ((bufferpos-pos) < len) len = (bufferpos-pos); for(i=0; ii+1) + { + if(argv[i+1]) + { + //unit=strtoul(argv[i+1],NULL,10); + unit=atoi(argv[i+1]); + if(unit<4) + { + set_ahi_devide(unit); + } + else + { + printf("AHI-unit %d out of range (0...3)\n",unit); + return 1; + } + } + else + { + printf("AHI-unit is NULL-Ptr!\n"); + return 1; + } + } + else + { + printf("missing AHI unit\n"); + return 1; + } + i++; + } else +#endif { PrintUsage(); return 1; @@ -256,7 +351,22 @@ int main(int argc, char **argv) PrintUsage(); return 1; } +{ + //AF STOPWATCH + D( + StopStopWatch(sw_main); + { + #define PRINT_STOPWATCH(x) printf("Dauer " #x " : %6lums, (%2.2f%%)\n",StopWatchGetTotalMilliSeconds(x), 100.0*StopWatchGetTotalMilliSeconds(x)/main_ms); + unsigned long main_ms=StopWatchGetMilliSeconds(sw_main); + printf("Dauer main : %6lums\n",main_ms); + } + ) +D(printf("Sound berechnung nach %lld Sekunden\n",time(NULL)-StartZeit)); +extern int bufferpos; +D(printf("%s(): BufferPos=%d\n",__FUNCTION__,bufferpos)); +D(printf("%s(): GetBufferLength=%d\n",__FUNCTION__,GetBufferLength())); +} if (wavfilename != NULL) WriteWav(wavfilename, GetBuffer(), GetBufferLength()/50); else diff --git a/src/render.c b/src/render.c index 5d4e79d8..a88721fc 100755 --- a/src/render.c +++ b/src/render.c @@ -56,29 +56,31 @@ extern char *buffer; //timetable for more accurate c64 simulation int timetable[5][5] = { - {162, 167, 167, 127, 128}, - {226, 60, 60, 0, 0}, - {225, 60, 59, 0, 0}, - {200, 0, 0, 54, 55}, - {199, 0, 0, 54, 54} + {162, 167, 167, 127, 128}, + {226, 60, 60, 0, 0}, + {225, 60, 59, 0, 0}, + {200, 0, 0, 54, 55}, + {199, 0, 0, 54, 54} }; -static unsigned oldtimetableindex = 0; -void Output8BitAry(int index, unsigned char ary[5]) +void Output(int index, unsigned char A) { - int k; - bufferpos += timetable[oldtimetableindex][index]; - oldtimetableindex = index; - // write a little bit in advance - for(k=0; k<5; k++) - buffer[bufferpos/50 + k] = ary[k]; + static unsigned oldtimetableindex = 0; +// int k; + int local_bufferpos; // much faster if we use a local copy here 30s --> 13s for sam -wav hello.wav Hello, my name is sam. 1 2 3 4 5 6 7 8 9 0 + char *local_buffer_ptr; + bufferpos += timetable[oldtimetableindex][index]; + local_bufferpos=bufferpos/50; + local_buffer_ptr=&buffer[local_bufferpos]; + oldtimetableindex = index; + // write a little bit in advance +// for(k=0; k<5; k++) + *local_buffer_ptr++ = (A & 15)*16; // much faster if we use a local copy here + *local_buffer_ptr++ = (A & 15)*16; // much faster if we use a local copy here + *local_buffer_ptr++ = (A & 15)*16; // much faster if we use a local copy here + *local_buffer_ptr++ = (A & 15)*16; // much faster if we use a local copy here + *local_buffer_ptr++ = (A & 15)*16; // much faster if we use a local copy here } -void Output8Bit(int index, unsigned char A) -{ - unsigned char ary[5] = {A,A,A,A,A}; - Output8BitAry(index, ary); -} - @@ -97,38 +99,61 @@ void Output8Bit(int index, unsigned char A) // 174=amplitude3 unsigned char Read(unsigned char p, unsigned char Y) { - switch(p) - { - case 168: return pitches[Y]; - case 169: return frequency1[Y]; - case 170: return frequency2[Y]; - case 171: return frequency3[Y]; - case 172: return amplitude1[Y]; - case 173: return amplitude2[Y]; - case 174: return amplitude3[Y]; - } - printf("Error reading to tables"); - return 0; + switch(p) + { + case 168: return pitches[Y]; + case 169: return frequency1[Y]; + case 170: return frequency2[Y]; + case 171: return frequency3[Y]; + case 172: return amplitude1[Y]; + case 173: return amplitude2[Y]; + case 174: return amplitude3[Y]; + } + printf("Error reading to tables"); + return 0; } void Write(unsigned char p, unsigned char Y, unsigned char value) { - switch(p) - { - case 168: pitches[Y] = value; return; - case 169: frequency1[Y] = value; return; - case 170: frequency2[Y] = value; return; - case 171: frequency3[Y] = value; return; - case 172: amplitude1[Y] = value; return; - case 173: amplitude2[Y] = value; return; - case 174: amplitude3[Y] = value; return; - } - printf("Error writing to tables\n"); + switch(p) + { + case 168: pitches[Y] = value; return; + case 169: frequency1[Y] = value; return; + case 170: frequency2[Y] = value; return; + case 171: frequency3[Y] = value; return; + case 172: amplitude1[Y] = value; return; + case 173: amplitude2[Y] = value; return; + case 174: amplitude3[Y] = value; return; + } + printf("Error writing to tables\n"); } +#ifdef __AMIGA__ + + #include + void Render_000(void); + void Render_020(void); + + void (*Render_Function)(void); + + void SetCpuSpecificFunctions(void) + { + extern struct ExecBase *SysBase; + if(SysBase->AttnFlags&AFF_68020) + { + Render_Function=Render_020; + } + else + { + Render_Function=Render_000; + } + } +#endif + + // ------------------------------------------------------------------------- //Code48227 // Render a sampled sound from the sampleTable. @@ -187,154 +212,154 @@ void Write(unsigned char p, unsigned char Y, unsigned char value) // Code48227() void RenderSample(unsigned char *mem66) { - int tempA; - // current phoneme's index - mem49 = Y; + int tempA; + // current phoneme's index + mem49 = Y; - // mask low three bits and subtract 1 get value to - // convert 0 bits on unvoiced samples. - A = mem39&7; - X = A-1; + // mask low three bits and subtract 1 get value to + // convert 0 bits on unvoiced samples. + A = mem39&7; + X = A-1; // store the result - mem56 = X; + mem56 = X; - // determine which offset to use from table { 0x18, 0x1A, 0x17, 0x17, 0x17 } - // T, S, Z 0 0x18 - // CH, J, SH, ZH 1 0x1A - // P, F*, V, TH, DH 2 0x17 - // /H 3 0x17 - // /X 4 0x17 + // determine which offset to use from table { 0x18, 0x1A, 0x17, 0x17, 0x17 } + // T, S, Z 0 0x18 + // CH, J, SH, ZH 1 0x1A + // P, F*, V, TH, DH 2 0x17 + // /H 3 0x17 + // /X 4 0x17 // get value from the table - mem53 = tab48426[X]; - mem47 = X; //46016+mem[56]*256 + mem53 = tab48426[X]; + mem47 = X; //46016+mem[56]*256 - // voiced sample? - A = mem39 & 248; - if(A == 0) - { + // voiced sample? + A = mem39 & 248; + if(A == 0) + { // voiced phoneme: Z*, ZH, V*, DH - Y = mem49; - A = pitches[mem49] >> 4; + Y = mem49; + A = pitches[mem49] >> 4; - // jump to voiced portion - goto pos48315; - } + // jump to voiced portion + goto pos48315; + } - Y = A ^ 255; + Y = A ^ 255; pos48274: // step through the 8 bits in the sample - mem56 = 8; + mem56 = 8; - // get the next sample from the table + // get the next sample from the table // mem47*256 = offset to start of samples - A = sampleTable[mem47*256+Y]; + A = sampleTable[mem47*256+Y]; pos48280: // left shift to get the high bit - tempA = A; - A = A << 1; - //48281: BCC 48290 + tempA = A; + A = A << 1; + //48281: BCC 48290 - // bit not set? - if ((tempA & 128) == 0) - { + // bit not set? + if ((tempA & 128) == 0) + { // convert the bit to value from table - X = mem53; - //mem[54296] = X; + X = mem53; + //mem[54296] = X; // output the byte - Output8Bit(1, (X&0x0f) * 16); - // if X != 0, exit loop - if(X != 0) goto pos48296; - } + Output(1, X); + // if X != 0, exit loop + if(X != 0) goto pos48296; + } - // output a 5 for the on bit - Output8Bit(2, 5 * 16); + // output a 5 for the on bit + Output(2, 5); - //48295: NOP + //48295: NOP pos48296: - X = 0; + X = 0; // decrement counter - mem56--; + mem56--; - // if not done, jump to top of loop - if (mem56 != 0) goto pos48280; + // if not done, jump to top of loop + if (mem56 != 0) goto pos48280; - // increment position - Y++; - if (Y != 0) goto pos48274; + // increment position + Y++; + if (Y != 0) goto pos48274; - // restore values and return - mem44 = 1; - Y = mem49; - return; + // restore values and return + mem44 = 1; + Y = mem49; + return; - unsigned char phase1; + unsigned char phase1; pos48315: // handle voiced samples here // number of samples? - phase1 = A ^ 255; + phase1 = A ^ 255; - Y = *mem66; - do - { - //pos48321: + Y = *mem66; + do + { + //pos48321: // shift through all 8 bits - mem56 = 8; - //A = Read(mem47, Y); + mem56 = 8; + //A = Read(mem47, Y); - // fetch value from table - A = sampleTable[mem47*256+Y]; + // fetch value from table + A = sampleTable[mem47*256+Y]; // loop 8 times - //pos48327: - do - { - //48327: ASL A - //48328: BCC 48337 - - // left shift and check high bit - tempA = A; - A = A << 1; - if ((tempA & 128) != 0) - { + //pos48327: + do + { + //48327: ASL A + //48328: BCC 48337 + + // left shift and check high bit + tempA = A; + A = A << 1; + if ((tempA & 128) != 0) + { // if bit set, output 26 - X = 26; - Output8Bit(3, (X&0xf)*16); - } else - { - //timetable 4 - // bit is not set, output a 6 - X=6; - Output8Bit(4, (X&0xf)*16); - } - - mem56--; - } while(mem56 != 0); + X = 26; + Output(3, X); + } else + { + //timetable 4 + // bit is not set, output a 6 + X=6; + Output(4, X); + } + + mem56--; + } while(mem56 != 0); // move ahead in the table - Y++; + Y++; - // continue until counter done - phase1++; + // continue until counter done + phase1++; - } while (phase1 != 0); - // if (phase1 != 0) goto pos48321; + } while (phase1 != 0); + // if (phase1 != 0) goto pos48321; - // restore values and return - A = 1; - mem44 = 1; - *mem66 = Y; - Y = mem49; - return; + // restore values and return + A = 1; + mem44 = 1; + *mem66 = Y; + Y = mem49; + return; } @@ -358,20 +383,24 @@ void RenderSample(unsigned char *mem66) //void Code47574() void Render() { - unsigned char phase1 = 0; //mem43 - unsigned char phase2=0; - unsigned char phase3=0; - unsigned char mem66=0; - unsigned char mem38=0; - unsigned char mem40=0; - unsigned char speedcounter=0; //mem45 - unsigned char mem48=0; - int i; - if (phonemeIndexOutput[0] == 255) return; //exit if no data - - A = 0; - X = 0; - mem44 = 0; +#ifdef __AMIGA__ + Render_Function(); +#else + unsigned char phase1 = 0; //mem43 + unsigned char phase2; + unsigned char phase3; + unsigned char mem66; + unsigned char mem38; + unsigned char mem40; + unsigned char speedcounter; //mem45 + unsigned char mem48; + int i; + int carry; + if (phonemeIndexOutput[0] == 255) return; //exit if no data + + A = 0; + X = 0; + mem44 = 0; // CREATE FRAMES @@ -387,58 +416,58 @@ void Render() do { // get the index - Y = mem44; - // get the phoneme at the index - A = phonemeIndexOutput[mem44]; - mem56 = A; + Y = mem44; + // get the phoneme at the index + A = phonemeIndexOutput[mem44]; + mem56 = A; - // if terminal phoneme, exit the loop - if (A == 255) break; + // if terminal phoneme, exit the loop + if (A == 255) break; - // period phoneme *. - if (A == 1) - { + // period phoneme *. + if (A == 1) + { // add rising inflection - A = 1; - mem48 = 1; - //goto pos48376; - AddInflection(mem48, phase1); - } - /* - if (A == 2) goto pos48372; - */ - - // question mark phoneme? - if (A == 2) - { + A = 1; + mem48 = 1; + //goto pos48376; + AddInflection(mem48, phase1); + } + /* + if (A == 2) goto pos48372; + */ + + // question mark phoneme? + if (A == 2) + { // create falling inflection - mem48 = 255; - AddInflection(mem48, phase1); - } - // pos47615: + mem48 = 255; + AddInflection(mem48, phase1); + } + // pos47615: // get the stress amount (more stress = higher pitch) - phase1 = tab47492[stressOutput[Y] + 1]; + phase1 = tab47492[stressOutput[Y] + 1]; // get number of frames to write - phase2 = phonemeLengthOutput[Y]; - Y = mem56; - - // copy from the source to the frames list - do - { - frequency1[X] = freq1data[Y]; // F1 frequency - frequency2[X] = freq2data[Y]; // F2 frequency - frequency3[X] = freq3data[Y]; // F3 frequency - amplitude1[X] = ampl1data[Y]; // F1 amplitude - amplitude2[X] = ampl2data[Y]; // F2 amplitude - amplitude3[X] = ampl3data[Y]; // F3 amplitude - sampledConsonantFlag[X] = sampledConsonantFlags[Y]; // phoneme data for sampled consonants - pitches[X] = pitch + phase1; // pitch - X++; - phase2--; - } while(phase2 != 0); - mem44++; + phase2 = phonemeLengthOutput[Y]; + Y = mem56; + + // copy from the source to the frames list + do + { + frequency1[X] = freq1data[Y]; // F1 frequency + frequency2[X] = freq2data[Y]; // F2 frequency + frequency3[X] = freq3data[Y]; // F3 frequency + amplitude1[X] = ampl1data[Y]; // F1 amplitude + amplitude2[X] = ampl2data[Y]; // F2 amplitude + amplitude3[X] = ampl3data[Y]; // F3 amplitude + sampledConsonantFlag[X] = sampledConsonantFlags[Y]; // phoneme data for sampled consonants + pitches[X] = pitch + phase1; // pitch + X++; + phase2--; + } while(phase2 != 0); + mem44++; } while(mem44 != 0); // ------------------- //pos47694: @@ -572,65 +601,72 @@ do // 241 2 10 2 65 1 96 59 * <-- OutBlendFrames = 1 // 241 0 6 0 73 0 99 61 - A = 0; - mem44 = 0; - mem49 = 0; // mem49 starts at as 0 - X = 0; - while(1) //while No. 1 - { + A = 0; + mem44 = 0; + mem49 = 0; // mem49 starts at as 0 + X = 0; + while(1) //while No. 1 + { +#ifdef __AMIGA__ + __chkabort(); /* look for CTRL-C */ +#endif // get the current and following phoneme - Y = phonemeIndexOutput[X]; - A = phonemeIndexOutput[X+1]; - X++; + Y = phonemeIndexOutput[X]; + A = phonemeIndexOutput[X+1]; + X++; - // exit loop at end token - if (A == 255) break;//goto pos47970; + // exit loop at end token + if (A == 255) break;//goto pos47970; // get the ranking of each phoneme - X = A; - mem56 = blendRank[A]; - A = blendRank[Y]; + X = A; + mem56 = blendRank[A]; + A = blendRank[Y]; - // compare the rank - lower rank value is stronger - if (A == mem56) - { + // compare the rank - lower rank value is stronger + if (A == mem56) + { // same rank, so use out blend lengths from each phoneme - phase1 = outBlendLength[Y]; - phase2 = outBlendLength[X]; - } else - if (A < mem56) - { + phase1 = outBlendLength[Y]; + phase2 = outBlendLength[X]; + } else + if (A < mem56) + { // first phoneme is stronger, so us it's blend lengths - phase1 = inBlendLength[X]; - phase2 = outBlendLength[X]; - } else - { + phase1 = inBlendLength[X]; + phase2 = outBlendLength[X]; + } else + { // second phoneme is stronger, so use it's blend lengths // note the out/in are swapped - phase1 = outBlendLength[Y]; - phase2 = inBlendLength[Y]; - } - - Y = mem44; - A = mem49 + phonemeLengthOutput[mem44]; // A is mem49 + length - mem49 = A; // mem49 now holds length + position - A = A + phase2; //Maybe Problem because of carry flag - - //47776: ADC 42 - speedcounter = A; - mem47 = 168; - phase3 = mem49 - phase1; // what is mem49 - A = phase1 + phase2; // total transition? - mem38 = A; - - X = A; - X -= 2; - if ((X & 128) == 0) - do //while No. 2 - { - //pos47810: + phase1 = outBlendLength[Y]; + phase2 = inBlendLength[Y]; + } + + Y = mem44; + A = mem49 + phonemeLengthOutput[mem44]; // A is mem49 + length + mem49 = A; // mem49 now holds length + position + A = A + phase2; //Maybe Problem because of carry flag + + //47776: ADC 42 + speedcounter = A; + mem47 = 168; + phase3 = mem49 - phase1; // what is mem49 + A = phase1 + phase2; // total transition? + mem38 = A; + + X = A; + X -= 2; + if ((X & 128) == 0) + do //while No. 2 + { +#ifdef __AMIGA__ + __chkabort(); /* look for CTRL-C */ +#endif + + //pos47810: // mem47 is used to index the tables: // 168 pitches[] @@ -641,98 +677,100 @@ do // 173 amplitude2 // 174 amplitude3 - mem40 = mem38; + mem40 = mem38; - if (mem47 == 168) // pitch - { + if (mem47 == 168) // pitch + { // unlike the other values, the pitches[] interpolates from // the middle of the current phoneme to the middle of the // next phoneme - unsigned char mem36, mem37; - // half the width of the current phoneme - mem36 = phonemeLengthOutput[mem44] >> 1; - // half the width of the next phoneme - mem37 = phonemeLengthOutput[mem44+1] >> 1; - // sum the values - mem40 = mem36 + mem37; // length of both halves - mem37 += mem49; // center of next phoneme - mem36 = mem49 - mem36; // center index of current phoneme - A = Read(mem47, mem37); // value at center of next phoneme - end interpolation value - //A = mem[address]; - - Y = mem36; // start index of interpolation - mem53 = A - Read(mem47, mem36); // value to center of current phoneme - } else - { + unsigned char mem36, mem37; + // half the width of the current phoneme + mem36 = phonemeLengthOutput[mem44] >> 1; + // half the width of the next phoneme + mem37 = phonemeLengthOutput[mem44+1] >> 1; + // sum the values + mem40 = mem36 + mem37; // length of both halves + mem37 += mem49; // center of next phoneme + mem36 = mem49 - mem36; // center index of current phoneme + A = Read(mem47, mem37); // value at center of next phoneme - end interpolation value + //A = mem[address]; + + Y = mem36; // start index of interpolation + mem53 = A - Read(mem47, mem36); // value to center of current phoneme + } else + { // value to interpolate to - A = Read(mem47, speedcounter); - // position to start interpolation from - Y = phase3; - // value to interpolate from - mem53 = A - Read(mem47, phase3); - } - - //Code47503(mem40); - // ML : Code47503 is division with remainder, and mem50 gets the sign - - // calculate change per frame - signed char m53 = (signed char)mem53; - mem50 = mem53 & 128; - unsigned char m53abs = abs(m53); - mem51 = m53abs % mem40; //abs((char)m53) % mem40; - mem53 = (unsigned char)((signed char)(m53) / mem40); + A = Read(mem47, speedcounter); + // position to start interpolation from + Y = phase3; + // value to interpolate from + mem53 = A - Read(mem47, phase3); + } + + //Code47503(mem40); + // ML : Code47503 is division with remainder, and mem50 gets the sign + + // calculate change per frame + mem50 = (((char)(mem53) < 0) ? 128 : 0); + mem51 = abs((char)mem53) % mem40; + mem53 = (unsigned char)((char)(mem53) / mem40); // interpolation range - X = mem40; // number of frames to interpolate over - Y = phase3; // starting frame + X = mem40; // number of frames to interpolate over + Y = phase3; // starting frame // linearly interpolate values - mem56 = 0; - //47907: CLC - //pos47908: - while(1) //while No. 3 - { - A = Read(mem47, Y) + mem53; //carry alway cleared - - mem48 = A; - Y++; - X--; - if(X == 0) break; - - mem56 += mem51; - if (mem56 >= mem40) //??? - { - mem56 -= mem40; //carry? is set - //if ((mem56 & 128)==0) - if ((mem50 & 128)==0) - { - //47935: BIT 50 - //47937: BMI 47943 - if(mem48 != 0) mem48++; - } else mem48--; - } - //pos47945: - Write(mem47, Y, mem48); - } //while No. 3 - - //pos47952: - mem47++; - //if (mem47 != 175) goto pos47810; - } while (mem47 != 175); //while No. 2 - //pos47963: - mem44++; - X = mem44; - } //while No. 1 - - //goto pos47701; - //pos47970: + mem56 = 0; + //47907: CLC + //pos47908: + while(1) //while No. 3 + { +#ifdef __AMIGA__ + __chkabort(); /* look for CTRL-C */ +#endif + + A = Read(mem47, Y) + mem53; //carry alway cleared + + mem48 = A; + Y++; + X--; + if(X == 0) break; + + mem56 += mem51; + if (mem56 >= mem40) //??? + { + mem56 -= mem40; //carry? is set + //if ((mem56 & 128)==0) + if ((mem50 & 128)==0) + { + //47935: BIT 50 + //47937: BMI 47943 + if(mem48 != 0) mem48++; + } else mem48--; + } + //pos47945: + Write(mem47, Y, mem48); + } //while No. 3 + + //pos47952: + mem47++; + //if (mem47 != 175) goto pos47810; + } while (mem47 != 175); //while No. 2 + //pos47963: + mem44++; + X = mem44; + } //while No. 1 + + //goto pos47701; + //pos47970: // add the length of this phoneme - mem48 = mem49 + phonemeLengthOutput[mem44]; + mem48 = mem49 + phonemeLengthOutput[mem44]; // ASSIGN PITCH CONTOUR @@ -742,45 +780,45 @@ do // pitch level (monotone). - // don't adjust pitch if in sing mode - if (!singmode) - { + // don't adjust pitch if in sing mode + if (!singmode) + { // iterate through the buffer - for(i=0; i<256; i++) { + for(i=0; i<256; i++) { // subtract half the frequency of the formant 1. // this adds variety to the voice - pitches[i] -= (frequency1[i] >> 1); + pitches[i] -= (frequency1[i] >> 1); } - } + } - phase1 = 0; - phase2 = 0; - phase3 = 0; - mem49 = 0; - speedcounter = 72; //sam standard speed + phase1 = 0; + phase2 = 0; + phase3 = 0; + mem49 = 0; + speedcounter = 72; //sam standard speed // RESCALE AMPLITUDE // // Rescale volume from a linear scale to decibels. // - //amplitude rescaling - for(i=255; i>=0; i--) - { - amplitude1[i] = amplitudeRescale[amplitude1[i]]; - amplitude2[i] = amplitudeRescale[amplitude2[i]]; - amplitude3[i] = amplitudeRescale[amplitude3[i]]; - } + //amplitude rescaling + for(i=255; i>=0; i--) + { + amplitude1[i] = amplitudeRescale[amplitude1[i]]; + amplitude2[i] = amplitudeRescale[amplitude2[i]]; + amplitude3[i] = amplitudeRescale[amplitude3[i]]; + } - Y = 0; - A = pitches[0]; - mem44 = A; - X = A; - mem38 = A - (A>>2); // 3/4*A ??? + Y = 0; + A = pitches[0]; + mem44 = A; + X = A; + mem38 = A - (A>>2); // 3/4*A ??? if (debug) { - PrintOutput(sampledConsonantFlag, frequency1, frequency2, frequency3, amplitude1, amplitude2, amplitude3, pitches); + PrintOutput(sampledConsonantFlag, frequency1, frequency2, frequency3, amplitude1, amplitude2, amplitude3, pitches); } // PROCESS THE FRAMES @@ -792,154 +830,144 @@ if (debug) // To simulate them being driven by the glottal pulse, the waveforms are // reset at the beginning of each glottal pulse. - //finally the loop for sound output - //pos48078: - while(1) - { + //finally the loop for sound output + //pos48078: + while(1) + { // get the sampled information on the phoneme - A = sampledConsonantFlag[Y]; - mem39 = A; + A = sampledConsonantFlag[Y]; + mem39 = A; - // unvoiced sampled phoneme? - A = A & 248; - if(A != 0) - { + // unvoiced sampled phoneme? + A = A & 248; + if(A != 0) + { // render the sample for the phoneme - RenderSample(&mem66); + RenderSample(&mem66); - // skip ahead two in the phoneme buffer - Y += 2; - mem48 -= 2; - } else - { + // skip ahead two in the phoneme buffer + Y += 2; + mem48 -= 2; + } else + { // simulate the glottal pulse and formants - unsigned char ary[5]; - unsigned int p1 = phase1 * 256; // Fixed point integers because we need to divide later on - unsigned int p2 = phase2 * 256; - unsigned int p3 = phase3 * 256; - int k; - for (k=0; k<5; k++) { - signed char sp1 = (signed char)sinus[0xff & (p1>>8)]; - signed char sp2 = (signed char)sinus[0xff & (p2>>8)]; - signed char rp3 = (signed char)rectangle[0xff & (p3>>8)]; - signed int sin1 = sp1 * ((unsigned char)amplitude1[Y] & 0x0f); - signed int sin2 = sp2 * ((unsigned char)amplitude2[Y] & 0x0f); - signed int rect = rp3 * ((unsigned char)amplitude3[Y] & 0x0f); - signed int mux = sin1 + sin2 + rect; - mux /= 32; - mux += 128; // Go from signed to unsigned amplitude - ary[k] = mux; - p1 += frequency1[Y] * 256 / 4; // Compromise, this becomes a shift and works well - p2 += frequency2[Y] * 256 / 4; - p3 += frequency3[Y] * 256 / 4; - } - // output the accumulated value - Output8BitAry(0, ary); - speedcounter--; - if (speedcounter != 0) goto pos48155; - Y++; //go to next amplitude - - // decrement the frame count - mem48--; - } - - // if the frame count is zero, exit the loop - if(mem48 == 0) return; - speedcounter = speed; + mem56 = multtable[sinus[phase1] | amplitude1[Y]]; + + carry = 0; + if ((mem56+multtable[sinus[phase2] | amplitude2[Y]] ) > 255) carry = 1; + mem56 += multtable[sinus[phase2] | amplitude2[Y]]; + A = mem56 + multtable[rectangle[phase3] | amplitude3[Y]] + (carry?1:0); + A = ((A + 136) & 255) >> 4; //there must be also a carry + //mem[54296] = A; + + // output the accumulated value + Output(0, A); + speedcounter--; + if (speedcounter != 0) goto pos48155; + Y++; //go to next amplitude + + // decrement the frame count + mem48--; + } + + // if the frame count is zero, exit the loop + if(mem48 == 0) return; + speedcounter = speed; pos48155: // decrement the remaining length of the glottal pulse - mem44--; + mem44--; - // finished with a glottal pulse? - if(mem44 == 0) - { + // finished with a glottal pulse? + if(mem44 == 0) + { pos48159: // fetch the next glottal pulse length - A = pitches[Y]; - mem44 = A; - A = A - (A>>2); - mem38 = A; - - // reset the formant wave generators to keep them in - // sync with the glottal pulse - phase1 = 0; - phase2 = 0; - phase3 = 0; - continue; - } - - // decrement the count - mem38--; - - // is the count non-zero and the sampled flag is zero? - if((mem38 != 0) || (mem39 == 0)) - { + A = pitches[Y]; + mem44 = A; + A = A - (A>>2); + mem38 = A; + + // reset the formant wave generators to keep them in + // sync with the glottal pulse + phase1 = 0; + phase2 = 0; + phase3 = 0; + continue; + } + + // decrement the count + mem38--; + + // is the count non-zero and the sampled flag is zero? + if((mem38 != 0) || (mem39 == 0)) + { // reset the phase of the formants to match the pulse - phase1 += frequency1[Y]; - phase2 += frequency2[Y]; - phase3 += frequency3[Y]; - continue; - } + phase1 += frequency1[Y]; + phase2 += frequency2[Y]; + phase3 += frequency3[Y]; + continue; + } - // voiced sampled phonemes interleave the sample with the - // glottal pulse. The sample flag is non-zero, so render - // the sample for the phoneme. - RenderSample(&mem66); - goto pos48159; - } //while + // voiced sampled phonemes interleave the sample with the + // glottal pulse. The sample flag is non-zero, so render + // the sample for the phoneme. + RenderSample(&mem66); + goto pos48159; + } //while // The following code is never reached. It's left over from when // the voiced sample code was part of this loop, instead of part // of RenderSample(); - //pos48315: - int tempA; - phase1 = A ^ 255; - Y = mem66; - do - { - //pos48321: - - mem56 = 8; - A = Read(mem47, Y); - - //pos48327: - do - { - //48327: ASL A - //48328: BCC 48337 - tempA = A; - A = A << 1; - if ((tempA & 128) != 0) - { - X = 26; - // mem[54296] = X; - bufferpos += 150; - buffer[bufferpos/50] = (X & 15)*16; - } else - { - //mem[54296] = 6; - X=6; - bufferpos += 150; - buffer[bufferpos/50] = (X & 15)*16; - } - - for(X = wait2; X>0; X--); //wait - mem56--; - } while(mem56 != 0); - - Y++; - phase1++; - - } while (phase1 != 0); - // if (phase1 != 0) goto pos48321; - A = 1; - mem44 = 1; - mem66 = Y; - Y = mem49; - return; + //pos48315: + int tempA; + phase1 = A ^ 255; + Y = mem66; + do + { + //pos48321: + + mem56 = 8; + A = Read(mem47, Y); + + //pos48327: + do + { + //48327: ASL A + //48328: BCC 48337 + tempA = A; + A = A << 1; + if ((tempA & 128) != 0) + { + X = 26; + // mem[54296] = X; + bufferpos += 150; + buffer[bufferpos/50] = (X & 15)*16; + } else + { + //mem[54296] = 6; + X=6; + bufferpos += 150; + buffer[bufferpos/50] = (X & 15)*16; + } + + for(X = wait2; X>0; X--); //wait + mem56--; + } while(mem56 != 0); + + Y++; + phase1++; + + } while (phase1 != 0); + // if (phase1 != 0) goto pos48321; + A = 1; + mem44 = 1; + mem66 = Y; + Y = mem49; + return; +#endif } @@ -949,46 +977,46 @@ if (debug) void AddInflection(unsigned char mem48, unsigned char phase1) { - //pos48372: - // mem48 = 255; + //pos48372: + // mem48 = 255; //pos48376: // store the location of the punctuation - mem49 = X; - A = X; - int Atemp = A; + mem49 = X; + A = X; + int Atemp = A; - // backup 30 frames - A = A - 30; - // if index is before buffer, point to start of buffer - if (Atemp <= 30) A=0; - X = A; + // backup 30 frames + A = A - 30; + // if index is before buffer, point to start of buffer + if (Atemp <= 30) A=0; + X = A; - // FIXME: Explain this fix better, it's not obvious - // ML : A =, fixes a problem with invalid pitch with '.' - while( (A=pitches[X]) == 127) X++; + // FIXME: Explain this fix better, it's not obvious + // ML : A =, fixes a problem with invalid pitch with '.' + while( (A=pitches[X]) == 127) X++; pos48398: - //48398: CLC - //48399: ADC 48 + //48398: CLC + //48399: ADC 48 - // add the inflection direction - A += mem48; - phase1 = A; + // add the inflection direction + A += mem48; + phase1 = A; - // set the inflection - pitches[X] = A; + // set the inflection + pitches[X] = A; pos48406: // increment the position - X++; + X++; - // exit if the punctuation has been reached - if (X == mem49) return; //goto pos47615; - if (pitches[X] == 255) goto pos48406; - A = phase1; - goto pos48398; + // exit if the punctuation has been reached + if (X == mem49) return; //goto pos47615; + if (pitches[X] == 255) goto pos48406; + A = phase1; + goto pos48398; } /* @@ -998,108 +1026,108 @@ void AddInflection(unsigned char mem48, unsigned char phase1) */ void SetMouthThroat(unsigned char mouth, unsigned char throat) { - unsigned char initialFrequency; - unsigned char newFrequency = 0; - //unsigned char mouth; //mem38880 - //unsigned char throat; //mem38881 - - // mouth formants (F1) 5..29 - unsigned char mouthFormants5_29[30] = { - 0, 0, 0, 0, 0, 10, - 14, 19, 24, 27, 23, 21, 16, 20, 14, 18, 14, 18, 18, - 16, 13, 15, 11, 18, 14, 11, 9, 6, 6, 6}; - - // throat formants (F2) 5..29 - unsigned char throatFormants5_29[30] = { - 255, 255, - 255, 255, 255, 84, 73, 67, 63, 40, 44, 31, 37, 45, 73, 49, - 36, 30, 51, 37, 29, 69, 24, 50, 30, 24, 83, 46, 54, 86}; - - // there must be no zeros in this 2 tables - // formant 1 frequencies (mouth) 48..53 - unsigned char mouthFormants48_53[6] = {19, 27, 21, 27, 18, 13}; - - // formant 2 frequencies (throat) 48..53 - unsigned char throatFormants48_53[6] = {72, 39, 31, 43, 30, 34}; - - unsigned char pos = 5; //mem39216 + unsigned char initialFrequency; + unsigned char newFrequency = 0; + //unsigned char mouth; //mem38880 + //unsigned char throat; //mem38881 + + // mouth formants (F1) 5..29 + unsigned char mouthFormants5_29[30] = { + 0, 0, 0, 0, 0, 10, + 14, 19, 24, 27, 23, 21, 16, 20, 14, 18, 14, 18, 18, + 16, 13, 15, 11, 18, 14, 11, 9, 6, 6, 6}; + + // throat formants (F2) 5..29 + unsigned char throatFormants5_29[30] = { + 255, 255, + 255, 255, 255, 84, 73, 67, 63, 40, 44, 31, 37, 45, 73, 49, + 36, 30, 51, 37, 29, 69, 24, 50, 30, 24, 83, 46, 54, 86}; + + // there must be no zeros in this 2 tables + // formant 1 frequencies (mouth) 48..53 + unsigned char mouthFormants48_53[6] = {19, 27, 21, 27, 18, 13}; + + // formant 2 frequencies (throat) 48..53 + unsigned char throatFormants48_53[6] = {72, 39, 31, 43, 30, 34}; + + unsigned char pos = 5; //mem39216 //pos38942: - // recalculate formant frequencies 5..29 for the mouth (F1) and throat (F2) - while(pos != 30) - { - // recalculate mouth frequency - initialFrequency = mouthFormants5_29[pos]; - if (initialFrequency != 0) newFrequency = trans(mouth, initialFrequency); - freq1data[pos] = newFrequency; - - // recalculate throat frequency - initialFrequency = throatFormants5_29[pos]; - if(initialFrequency != 0) newFrequency = trans(throat, initialFrequency); - freq2data[pos] = newFrequency; - pos++; - } + // recalculate formant frequencies 5..29 for the mouth (F1) and throat (F2) + while(pos != 30) + { + // recalculate mouth frequency + initialFrequency = mouthFormants5_29[pos]; + if (initialFrequency != 0) newFrequency = trans(mouth, initialFrequency); + freq1data[pos] = newFrequency; + + // recalculate throat frequency + initialFrequency = throatFormants5_29[pos]; + if(initialFrequency != 0) newFrequency = trans(throat, initialFrequency); + freq2data[pos] = newFrequency; + pos++; + } //pos39059: - // recalculate formant frequencies 48..53 - pos = 48; - Y = 0; + // recalculate formant frequencies 48..53 + pos = 48; + Y = 0; while(pos != 54) { - // recalculate F1 (mouth formant) - initialFrequency = mouthFormants48_53[Y]; - newFrequency = trans(mouth, initialFrequency); - freq1data[pos] = newFrequency; - - // recalculate F2 (throat formant) - initialFrequency = throatFormants48_53[Y]; - newFrequency = trans(throat, initialFrequency); - freq2data[pos] = newFrequency; - Y++; - pos++; - } + // recalculate F1 (mouth formant) + initialFrequency = mouthFormants48_53[Y]; + newFrequency = trans(mouth, initialFrequency); + freq1data[pos] = newFrequency; + + // recalculate F2 (throat formant) + initialFrequency = throatFormants48_53[Y]; + newFrequency = trans(throat, initialFrequency); + freq2data[pos] = newFrequency; + Y++; + pos++; + } } //return = (mem39212*mem39213) >> 1 unsigned char trans(unsigned char mem39212, unsigned char mem39213) { - //pos39008: - unsigned char carry; - int temp; - unsigned char mem39214, mem39215; - A = 0; - mem39215 = 0; - mem39214 = 0; - X = 8; - do - { - carry = mem39212 & 1; - mem39212 = mem39212 >> 1; - if (carry != 0) - { - /* - 39018: LSR 39212 - 39021: BCC 39033 - */ - carry = 0; - A = mem39215; - temp = (int)A + (int)mem39213; - A = A + mem39213; - if (temp > 255) carry = 1; - mem39215 = A; - } - temp = mem39215 & 1; - mem39215 = (mem39215 >> 1) | (carry?128:0); - carry = temp; - //39033: ROR 39215 - X--; - } while (X != 0); - temp = mem39214 & 128; - mem39214 = (mem39214 << 1) | (carry?1:0); - carry = temp; - temp = mem39215 & 128; - mem39215 = (mem39215 << 1) | (carry?1:0); - carry = temp; - - return mem39215; + //pos39008: + unsigned char carry; + int temp; + unsigned char mem39214, mem39215; + A = 0; + mem39215 = 0; + mem39214 = 0; + X = 8; + do + { + carry = mem39212 & 1; + mem39212 = mem39212 >> 1; + if (carry != 0) + { + /* + 39018: LSR 39212 + 39021: BCC 39033 + */ + carry = 0; + A = mem39215; + temp = (int)A + (int)mem39213; + A = A + mem39213; + if (temp > 255) carry = 1; + mem39215 = A; + } + temp = mem39215 & 1; + mem39215 = (mem39215 >> 1) | (carry?128:0); + carry = temp; + //39033: ROR 39215 + X--; + } while (X != 0); + temp = mem39214 & 128; + mem39214 = (mem39214 << 1) | (carry?1:0); + carry = temp; + temp = mem39215 & 128; + mem39215 = (mem39215 << 1) | (carry?1:0); + carry = temp; + + return mem39215; } diff --git a/src/render2.c b/src/render2.c new file mode 100644 index 00000000..79588153 --- /dev/null +++ b/src/render2.c @@ -0,0 +1,961 @@ + +#ifdef mc68020 + #warning __mc68020__ + #define CPU_TYPE(x) x##_020 // https://stackoverflow.com/questions/1253934/c-pre-processor-defining-for-generated-function-names + #define CPU(x) CPU_TYPE(x) +#elif __mc68000__ + #warning 68000 + #define CPU_TYPE(x) x##_000 // https://stackoverflow.com/questions/1253934/c-pre-processor-defining-for-generated-function-names + #define CPU(x) CPU_TYPE(x) +#else +#warning NO valid CPU defined + #define CPU_TYPE(x) x##_standard // https://stackoverflow.com/questions/1253934/c-pre-processor-defining-for-generated-function-names + #define CPU(x) CPU_TYPE(x) +#endif + +#ifdef DEBUG + #define D(x) x +#else + // for debug-prints. Can be activated with -DDEBUG in Makefile + #define D(x) +#endif + + +#include +#include +#include "debug.h" + +/* from RenderTas.h */ +extern unsigned char multtable[256]; +extern unsigned char tab48426[5]; +extern unsigned char sampleTable[0x500]; +extern unsigned char tab47492[11]; +extern unsigned char amplitudeRescale[17]; // 17 also in RenderTab.h +extern unsigned char blendRank[80]; +extern unsigned char outBlendLength[80]; +extern unsigned char inBlendLength[80]; + +extern unsigned char sampledConsonantFlags[256]; +extern unsigned char freq1data[80]; +extern unsigned char freq2data[80]; +extern unsigned char freq3data[80]; +extern unsigned char ampl1data[80]; +extern unsigned char ampl2data[80]; +extern unsigned char ampl3data[80]; +extern unsigned char sinus[256]; +extern unsigned char rectangle[256]; + + + +extern int debug; + +extern unsigned char wait2; + + +extern unsigned char A, X, Y; +extern unsigned char mem44; +extern unsigned char mem47; +extern unsigned char mem49; +extern unsigned char mem39; +extern unsigned char mem50; +extern unsigned char mem51; +extern unsigned char mem53; +extern unsigned char mem56; + +extern unsigned char speed; +extern unsigned char pitch; +extern int singmode; + +extern unsigned char phonemeIndexOutput[60]; //tab47296 +extern unsigned char stressOutput[60]; //tab47365 +extern unsigned char phonemeLengthOutput[60]; //tab47416 + +extern unsigned char pitches[256]; // tab43008 + +extern unsigned char frequency1[256]; +extern unsigned char frequency2[256]; +extern unsigned char frequency3[256]; + +extern unsigned char amplitude1[256]; +extern unsigned char amplitude2[256]; +extern unsigned char amplitude3[256]; + +void AddInflection(unsigned char mem48, unsigned char phase1); +unsigned char Read(unsigned char p, unsigned char Y); +void Write(unsigned char p, unsigned char Y, unsigned char value); + + +// contains the final soundbuffer +extern int bufferpos; +extern char *buffer; + +extern unsigned char sampledConsonantFlag[256]; // tab44800 + +//timetable for more accurate c64 simulation +static int timetable[5][8] = +{ + {162, 167, 167, 127, 128,0,0,0}, + {226, 60, 60, 0, 0,0,0,0}, + {225, 60, 59, 0, 0,0,0,0}, + {200, 0, 0, 54, 55,0,0,0}, + {199, 0, 0, 54, 54,0,0,0} +}; + +inline void CPU(Output)(int index, unsigned char A) +{ + extern struct UtilityBase *UtilityBase; + static unsigned oldtimetableindex = 0; +// int k; + int local_bufferpos; // much faster if we use a local copy here 30s --> 13s for sam -wav hello.wav Hello, my name is sam. 1 2 3 4 5 6 7 8 9 0 + char *local_buffer_ptr; + bufferpos += timetable[oldtimetableindex][index]; +// local_bufferpos=bufferpos/50; +local_bufferpos=((bufferpos*327U)>>14); //16384); // Durch 50,1 mal 327 durch 16384 // das beste! +//local_bufferpos=((bufferpos*327U)/16384); // Durch 50,1 mal 327 durch 16384 + +// local_bufferpos=((bufferpos<<8)+(bufferpos<<6)+(bufferpos<<3)-bufferpos) >>14; + +/* + asm( + " move.l %1,d0;" + " moveq #50,d1;" + " move.l %2,a0;" // UtilityBase + " jsr a0@(-150:W);" + " move.l d0,%0" + : "=r" (local_bufferpos) + : "r" (bufferpos), "r" (UtilityBase) + : "d0","d1", "a0" + ); +*/ + local_buffer_ptr=&buffer[local_bufferpos]; + oldtimetableindex = index; + // write a little bit in advance +// for(k=0; k<5; k++) + *local_buffer_ptr++ = (A & 15)*16; // much faster if we use a local copy here + *local_buffer_ptr++ = (A & 15)*16; // much faster if we use a local copy here + *local_buffer_ptr++ = (A & 15)*16; // much faster if we use a local copy here + *local_buffer_ptr++ = (A & 15)*16; // much faster if we use a local copy here + *local_buffer_ptr++ = (A & 15)*16; // much faster if we use a local copy here +} + + +// ------------------------------------------------------------------------- +//Code48227 +// Render a sampled sound from the sampleTable. +// +// Phoneme Sample Start Sample End +// 32: S* 15 255 +// 33: SH 257 511 +// 34: F* 559 767 +// 35: TH 583 767 +// 36: /H 903 1023 +// 37: /X 1135 1279 +// 38: Z* 84 119 +// 39: ZH 340 375 +// 40: V* 596 639 +// 41: DH 596 631 +// +// 42: CH +// 43: ** 399 511 +// +// 44: J* +// 45: ** 257 276 +// 46: ** +// +// 66: P* +// 67: ** 743 767 +// 68: ** +// +// 69: T* +// 70: ** 231 255 +// 71: ** +// +// The SampledPhonemesTable[] holds flags indicating if a phoneme is +// voiced or not. If the upper 5 bits are zero, the sample is voiced. +// +// Samples in the sampleTable are compressed, with bits being converted to +// bytes from high bit to low, as follows: +// +// unvoiced 0 bit -> X +// unvoiced 1 bit -> 5 +// +// voiced 0 bit -> 6 +// voiced 1 bit -> 24 +// +// Where X is a value from the table: +// +// { 0x18, 0x1A, 0x17, 0x17, 0x17 }; +// +// The index into this table is determined by masking off the lower +// 3 bits from the SampledPhonemesTable: +// +// index = (SampledPhonemesTable[i] & 7) - 1; +// +// For voices samples, samples are interleaved between voiced output. + + +// Code48227() +void CPU(RenderSample)(unsigned char *mem66) // 68000 or 68020 Version of this function +{ + D({ + static int Firsttime=1; + if(Firsttime) {Firsttime=0; printf("%s()\n",__FUNCTION__); } + }) + + int tempA; + // current phoneme's index + mem49 = Y; + + // mask low three bits and subtract 1 get value to + // convert 0 bits on unvoiced samples. + A = mem39&7; + X = A-1; + + // store the result + mem56 = X; + + // determine which offset to use from table { 0x18, 0x1A, 0x17, 0x17, 0x17 } + // T, S, Z 0 0x18 + // CH, J, SH, ZH 1 0x1A + // P, F*, V, TH, DH 2 0x17 + // /H 3 0x17 + // /X 4 0x17 + + // get value from the table + mem53 = tab48426[X]; + mem47 = X; //46016+mem[56]*256 + + // voiced sample? + A = mem39 & 248; + if(A == 0) + { + // voiced phoneme: Z*, ZH, V*, DH + Y = mem49; + A = pitches[mem49] >> 4; + + // jump to voiced portion + goto pos48315; + } + + Y = A ^ 255; +pos48274: + + // step through the 8 bits in the sample + mem56 = 8; + + // get the next sample from the table + // mem47*256 = offset to start of samples + A = sampleTable[mem47*256+Y]; +pos48280: + + // left shift to get the high bit + tempA = A; + A = A << 1; + //48281: BCC 48290 + + // bit not set? + if ((tempA & 128) == 0) + { + // convert the bit to value from table + X = mem53; + //mem[54296] = X; + // output the byte + CPU(Output)(1, X); + // if X != 0, exit loop + if(X != 0) goto pos48296; + } + + // output a 5 for the on bit + CPU(Output)(2, 5); + + //48295: NOP +pos48296: + + X = 0; + + // decrement counter + mem56--; + + // if not done, jump to top of loop + if (mem56 != 0) goto pos48280; + + // increment position + Y++; + if (Y != 0) goto pos48274; + + // restore values and return + mem44 = 1; + Y = mem49; + return; + + + unsigned char phase1; + +pos48315: +// handle voiced samples here + + // number of samples? + phase1 = A ^ 255; + + Y = *mem66; + do + { + //pos48321: + + // shift through all 8 bits + mem56 = 8; + //A = Read(mem47, Y); + + // fetch value from table + A = sampleTable[mem47*256+Y]; + + // loop 8 times + //pos48327: + do + { + //48327: ASL A + //48328: BCC 48337 + + // left shift and check high bit + tempA = A; + A = A << 1; + if ((tempA & 128) != 0) + { + // if bit set, output 26 + X = 26; + CPU(Output)(3, X); + } else + { + //timetable 4 + // bit is not set, output a 6 + X=6; + CPU(Output)(4, X); + } + + mem56--; + } while(mem56 != 0); + + // move ahead in the table + Y++; + + // continue until counter done + phase1++; + + } while (phase1 != 0); + // if (phase1 != 0) goto pos48321; + + // restore values and return + A = 1; + mem44 = 1; + *mem66 = Y; + Y = mem49; + return; +} + +// RENDER THE PHONEMES IN THE LIST +// +// The phoneme list is converted into sound through the steps: +// +// 1. Copy each phoneme number of times into the frames list, +// where each frame represents 10 milliseconds of sound. +// +// 2. Determine the transitions lengths between phonemes, and linearly +// interpolate the values across the frames. +// +// 3. Offset the pitches by the fundamental frequency. +// +// 4. Render the each frame. + + + +//void Code47574() +void CPU(Render)(void) // 68000 or 68020 Version of this function +{ + D({ + static int Firsttime=1; + if(Firsttime) {Firsttime=0; printf("%s()\n",__FUNCTION__); } + }) + + unsigned char phase1 = 0; //mem43 + unsigned char phase2; + unsigned char phase3; + unsigned char mem66; + unsigned char mem38; + unsigned char mem40; + unsigned char speedcounter; //mem45 + unsigned char mem48; + int i; + int carry; + if (phonemeIndexOutput[0] == 255) return; //exit if no data + + A = 0; + X = 0; + mem44 = 0; + + +// CREATE FRAMES +// +// The length parameter in the list corresponds to the number of frames +// to expand the phoneme to. Each frame represents 10 milliseconds of time. +// So a phoneme with a length of 7 = 7 frames = 70 milliseconds duration. +// +// The parameters are copied from the phoneme to the frame verbatim. + + +// pos47587: +do +{ + // get the index + Y = mem44; + // get the phoneme at the index + A = phonemeIndexOutput[mem44]; + mem56 = A; + + // if terminal phoneme, exit the loop + if (A == 255) break; + + // period phoneme *. + if (A == 1) + { + // add rising inflection + A = 1; + mem48 = 1; + //goto pos48376; + AddInflection(mem48, phase1); + } + /* + if (A == 2) goto pos48372; + */ + + // question mark phoneme? + if (A == 2) + { + // create falling inflection + mem48 = 255; + AddInflection(mem48, phase1); + } + // pos47615: + + // get the stress amount (more stress = higher pitch) + phase1 = tab47492[stressOutput[Y] + 1]; + + // get number of frames to write + phase2 = phonemeLengthOutput[Y]; + Y = mem56; + + // copy from the source to the frames list + do + { + frequency1[X] = freq1data[Y]; // F1 frequency + frequency2[X] = freq2data[Y]; // F2 frequency + frequency3[X] = freq3data[Y]; // F3 frequency + amplitude1[X] = ampl1data[Y]; // F1 amplitude + amplitude2[X] = ampl2data[Y]; // F2 amplitude + amplitude3[X] = ampl3data[Y]; // F3 amplitude + sampledConsonantFlag[X] = sampledConsonantFlags[Y]; // phoneme data for sampled consonants + pitches[X] = pitch + phase1; // pitch + X++; + phase2--; + } while(phase2 != 0); + mem44++; +} while(mem44 != 0); +// ------------------- +//pos47694: + +// CREATE TRANSITIONS +// +// Linear transitions are now created to smoothly connect the +// end of one sustained portion of a phoneme to the following +// phoneme. +// +// To do this, three tables are used: +// +// Table Purpose +// ========= ================================================== +// blendRank Determines which phoneme's blend values are used. +// +// blendOut The number of frames at the end of the phoneme that +// will be used to transition to the following phoneme. +// +// blendIn The number of frames of the following phoneme that +// will be used to transition into that phoneme. +// +// In creating a transition between two phonemes, the phoneme +// with the HIGHEST rank is used. Phonemes are ranked on how much +// their identity is based on their transitions. For example, +// vowels are and diphthongs are identified by their sustained portion, +// rather than the transitions, so they are given low values. In contrast, +// stop consonants (P, B, T, K) and glides (Y, L) are almost entirely +// defined by their transitions, and are given high rank values. +// +// Here are the rankings used by SAM: +// +// Rank Type Phonemes +// 2 All vowels IY, IH, etc. +// 5 Diphthong endings YX, WX, ER +// 8 Terminal liquid consonants LX, WX, YX, N, NX +// 9 Liquid consonants L, RX, W +// 10 Glide R, OH +// 11 Glide WH +// 18 Voiceless fricatives S, SH, F, TH +// 20 Voiced fricatives Z, ZH, V, DH +// 23 Plosives, stop consonants P, T, K, KX, DX, CH +// 26 Stop consonants J, GX, B, D, G +// 27-29 Stop consonants (internal) ** +// 30 Unvoiced consonants /H, /X and Q* +// 160 Nasal M +// +// To determine how many frames to use, the two phonemes are +// compared using the blendRank[] table. The phoneme with the +// higher rank is selected. In case of a tie, a blend of each is used: +// +// if blendRank[phoneme1] == blendRank[phomneme2] +// // use lengths from each phoneme +// outBlendFrames = outBlend[phoneme1] +// inBlendFrames = outBlend[phoneme2] +// else if blendRank[phoneme1] > blendRank[phoneme2] +// // use lengths from first phoneme +// outBlendFrames = outBlendLength[phoneme1] +// inBlendFrames = inBlendLength[phoneme1] +// else +// // use lengths from the second phoneme +// // note that in and out are SWAPPED! +// outBlendFrames = inBlendLength[phoneme2] +// inBlendFrames = outBlendLength[phoneme2] +// +// Blend lengths can't be less than zero. +// +// Transitions are assumed to be symetrical, so if the transition +// values for the second phoneme are used, the inBlendLength and +// outBlendLength values are SWAPPED. +// +// For most of the parameters, SAM interpolates over the range of the last +// outBlendFrames-1 and the first inBlendFrames. +// +// The exception to this is the Pitch[] parameter, which is interpolates the +// pitch from the CENTER of the current phoneme to the CENTER of the next +// phoneme. +// +// Here are two examples. First, For example, consider the word "SUN" (S AH N) +// +// Phoneme Duration BlendWeight OutBlendFrames InBlendFrames +// S 2 18 1 3 +// AH 8 2 4 4 +// N 7 8 1 2 +// +// The formant transitions for the output frames are calculated as follows: +// +// flags ampl1 freq1 ampl2 freq2 ampl3 freq3 pitch +// ------------------------------------------------ +// S +// 241 0 6 0 73 0 99 61 Use S (weight 18) for transition instead of AH (weight 2) +// 241 0 6 0 73 0 99 61 <-- (OutBlendFrames-1) = (1-1) = 0 frames +// AH +// 0 2 10 2 66 0 96 59 * <-- InBlendFrames = 3 frames +// 0 4 14 3 59 0 93 57 * +// 0 8 18 5 52 0 90 55 * +// 0 15 22 9 44 1 87 53 +// 0 15 22 9 44 1 87 53 +// 0 15 22 9 44 1 87 53 Use N (weight 8) for transition instead of AH (weight 2). +// 0 15 22 9 44 1 87 53 Since N is second phoneme, reverse the IN and OUT values. +// 0 11 17 8 47 1 98 56 * <-- (InBlendFrames-1) = (2-1) = 1 frames +// N +// 0 8 12 6 50 1 109 58 * <-- OutBlendFrames = 1 +// 0 5 6 5 54 0 121 61 +// 0 5 6 5 54 0 121 61 +// 0 5 6 5 54 0 121 61 +// 0 5 6 5 54 0 121 61 +// 0 5 6 5 54 0 121 61 +// 0 5 6 5 54 0 121 61 +// +// Now, consider the reverse "NUS" (N AH S): +// +// flags ampl1 freq1 ampl2 freq2 ampl3 freq3 pitch +// ------------------------------------------------ +// N +// 0 5 6 5 54 0 121 61 +// 0 5 6 5 54 0 121 61 +// 0 5 6 5 54 0 121 61 +// 0 5 6 5 54 0 121 61 +// 0 5 6 5 54 0 121 61 +// 0 5 6 5 54 0 121 61 Use N (weight 8) for transition instead of AH (weight 2) +// 0 5 6 5 54 0 121 61 <-- (OutBlendFrames-1) = (1-1) = 0 frames +// AH +// 0 8 11 6 51 0 110 59 * <-- InBlendFrames = 2 +// 0 11 16 8 48 0 99 56 * +// 0 15 22 9 44 1 87 53 Use S (weight 18) for transition instead of AH (weight 2) +// 0 15 22 9 44 1 87 53 Since S is second phoneme, reverse the IN and OUT values. +// 0 9 18 5 51 1 90 55 * <-- (InBlendFrames-1) = (3-1) = 2 +// 0 4 14 3 58 1 93 57 * +// S +// 241 2 10 2 65 1 96 59 * <-- OutBlendFrames = 1 +// 241 0 6 0 73 0 99 61 + + A = 0; + mem44 = 0; + mem49 = 0; // mem49 starts at as 0 + X = 0; + while(1) //while No. 1 + { +#ifdef __AMIGA__ + __chkabort(); /* look for CTRL-C */ +#endif + + // get the current and following phoneme + Y = phonemeIndexOutput[X]; + A = phonemeIndexOutput[X+1]; + X++; + + // exit loop at end token + if (A == 255) break;//goto pos47970; + + + // get the ranking of each phoneme + X = A; + mem56 = blendRank[A]; + A = blendRank[Y]; + + // compare the rank - lower rank value is stronger + if (A == mem56) + { + // same rank, so use out blend lengths from each phoneme + phase1 = outBlendLength[Y]; + phase2 = outBlendLength[X]; + } else + if (A < mem56) + { + // first phoneme is stronger, so us it's blend lengths + phase1 = inBlendLength[X]; + phase2 = outBlendLength[X]; + } else + { + // second phoneme is stronger, so use it's blend lengths + // note the out/in are swapped + phase1 = outBlendLength[Y]; + phase2 = inBlendLength[Y]; + } + + Y = mem44; + A = mem49 + phonemeLengthOutput[mem44]; // A is mem49 + length + mem49 = A; // mem49 now holds length + position + A = A + phase2; //Maybe Problem because of carry flag + + //47776: ADC 42 + speedcounter = A; + mem47 = 168; + phase3 = mem49 - phase1; // what is mem49 + A = phase1 + phase2; // total transition? + mem38 = A; + + X = A; + X -= 2; + if ((X & 128) == 0) + do //while No. 2 + { +#ifdef __AMIGA__ + __chkabort(); /* look for CTRL-C */ +#endif + + //pos47810: + + // mem47 is used to index the tables: + // 168 pitches[] + // 169 frequency1 + // 170 frequency2 + // 171 frequency3 + // 172 amplitude1 + // 173 amplitude2 + // 174 amplitude3 + + mem40 = mem38; + + if (mem47 == 168) // pitch + { + + // unlike the other values, the pitches[] interpolates from + // the middle of the current phoneme to the middle of the + // next phoneme + + unsigned char mem36, mem37; + // half the width of the current phoneme + mem36 = phonemeLengthOutput[mem44] >> 1; + // half the width of the next phoneme + mem37 = phonemeLengthOutput[mem44+1] >> 1; + // sum the values + mem40 = mem36 + mem37; // length of both halves + mem37 += mem49; // center of next phoneme + mem36 = mem49 - mem36; // center index of current phoneme + A = Read(mem47, mem37); // value at center of next phoneme - end interpolation value + //A = mem[address]; + + Y = mem36; // start index of interpolation + mem53 = A - Read(mem47, mem36); // value to center of current phoneme + } else + { + // value to interpolate to + A = Read(mem47, speedcounter); + // position to start interpolation from + Y = phase3; + // value to interpolate from + mem53 = A - Read(mem47, phase3); + } + + //Code47503(mem40); + // ML : Code47503 is division with remainder, and mem50 gets the sign + + // calculate change per frame + mem50 = (((char)(mem53) < 0) ? 128 : 0); + mem51 = abs((char)mem53) % mem40; + mem53 = (unsigned char)((char)(mem53) / mem40); + + // interpolation range + X = mem40; // number of frames to interpolate over + Y = phase3; // starting frame + + + // linearly interpolate values + + mem56 = 0; + //47907: CLC + //pos47908: + while(1) //while No. 3 + { +#ifdef __AMIGA__ + __chkabort(); /* look for CTRL-C */ +#endif + + A = Read(mem47, Y) + mem53; //carry alway cleared + + mem48 = A; + Y++; + X--; + if(X == 0) break; + + mem56 += mem51; + if (mem56 >= mem40) //??? + { + mem56 -= mem40; //carry? is set + //if ((mem56 & 128)==0) + if ((mem50 & 128)==0) + { + //47935: BIT 50 + //47937: BMI 47943 + if(mem48 != 0) mem48++; + } else mem48--; + } + //pos47945: + Write(mem47, Y, mem48); + } //while No. 3 + + //pos47952: + mem47++; + //if (mem47 != 175) goto pos47810; + } while (mem47 != 175); //while No. 2 + //pos47963: + mem44++; + X = mem44; + } //while No. 1 + + //goto pos47701; + //pos47970: + + // add the length of this phoneme + mem48 = mem49 + phonemeLengthOutput[mem44]; + + +// ASSIGN PITCH CONTOUR +// +// This subtracts the F1 frequency from the pitch to create a +// pitch contour. Without this, the output would be at a single +// pitch level (monotone). + + + // don't adjust pitch if in sing mode + if (!singmode) + { + // iterate through the buffer + for(i=0; i<256; i++) { + // subtract half the frequency of the formant 1. + // this adds variety to the voice + pitches[i] -= (frequency1[i] >> 1); + } + } + + phase1 = 0; + phase2 = 0; + phase3 = 0; + mem49 = 0; + speedcounter = 72; //sam standard speed + +// RESCALE AMPLITUDE +// +// Rescale volume from a linear scale to decibels. +// + + //amplitude rescaling + for(i=255; i>=0; i--) + { + amplitude1[i] = amplitudeRescale[amplitude1[i]]; + amplitude2[i] = amplitudeRescale[amplitude2[i]]; + amplitude3[i] = amplitudeRescale[amplitude3[i]]; + } + + Y = 0; + A = pitches[0]; + mem44 = A; + X = A; + mem38 = A - (A>>2); // 3/4*A ??? + +if (debug) +{ + PrintOutput(sampledConsonantFlag, frequency1, frequency2, frequency3, amplitude1, amplitude2, amplitude3, pitches); +} + +// PROCESS THE FRAMES +// +// In traditional vocal synthesis, the glottal pulse drives filters, which +// are attenuated to the frequencies of the formants. +// +// SAM generates these formants directly with sin and rectangular waves. +// To simulate them being driven by the glottal pulse, the waveforms are +// reset at the beginning of each glottal pulse. + + //finally the loop for sound output + //pos48078: + while(1) + { + unsigned char *local_multtable=multtable; + // get the sampled information on the phoneme + A = sampledConsonantFlag[Y]; + mem39 = A; + + // unvoiced sampled phoneme? + A = A & 248; + if(A != 0) + { + // render the sample for the phoneme + CPU(RenderSample)(&mem66); // call 68000 or 68020 Version of this function + + // skip ahead two in the phoneme buffer + Y += 2; + mem48 -= 2; + } else + { + // simulate the glottal pulse and formants + mem56 = multtable[sinus[phase1] | amplitude1[Y]]; + + carry = 0; + if ((mem56+local_multtable[sinus[phase2] | amplitude2[Y]] ) > 255) carry = 1; + mem56 += local_multtable[sinus[phase2] | amplitude2[Y]]; + A = mem56 + local_multtable[rectangle[phase3] | amplitude3[Y]] + (carry?1:0); + A = ((A + 136) & 255) >> 4; //there must be also a carry + //mem[54296] = A; + + // output the accumulated value + CPU(Output)(0, A); + speedcounter--; + if (speedcounter != 0) goto pos48155; + Y++; //go to next amplitude + + // decrement the frame count + mem48--; + } + + // if the frame count is zero, exit the loop + if(mem48 == 0) return; + speedcounter = speed; +pos48155: + + // decrement the remaining length of the glottal pulse + mem44--; + + // finished with a glottal pulse? + if(mem44 == 0) + { +pos48159: + // fetch the next glottal pulse length + A = pitches[Y]; + mem44 = A; + A = A - (A>>2); + mem38 = A; + + // reset the formant wave generators to keep them in + // sync with the glottal pulse + phase1 = 0; + phase2 = 0; + phase3 = 0; + continue; + } + + // decrement the count + mem38--; + + // is the count non-zero and the sampled flag is zero? + if((mem38 != 0) || (mem39 == 0)) + { + // reset the phase of the formants to match the pulse + phase1 += frequency1[Y]; + phase2 += frequency2[Y]; + phase3 += frequency3[Y]; + continue; + } + + // voiced sampled phonemes interleave the sample with the + // glottal pulse. The sample flag is non-zero, so render + // the sample for the phoneme. + CPU(RenderSample)(&mem66); // call 68000 or 68020 Version of this function + goto pos48159; + } //while + + + // The following code is never reached. It's left over from when + // the voiced sample code was part of this loop, instead of part + // of RenderSample(); + + //pos48315: + int tempA; + phase1 = A ^ 255; + Y = mem66; + do + { + //pos48321: + + mem56 = 8; + A = Read(mem47, Y); + + //pos48327: + do + { + //48327: ASL A + //48328: BCC 48337 + tempA = A; + A = A << 1; + if ((tempA & 128) != 0) + { + X = 26; + // mem[54296] = X; + bufferpos += 150; + buffer[bufferpos/50] = (X & 15)*16; + } else + { + //mem[54296] = 6; + X=6; + bufferpos += 150; + buffer[bufferpos/50] = (X & 15)*16; + } + + for(X = wait2; X>0; X--); //wait + mem56--; + } while(mem56 != 0); + + Y++; + phase1++; + + } while (phase1 != 0); + // if (phase1 != 0) goto pos48321; + A = 1; + mem44 = 1; + mem66 = Y; + Y = mem49; + return; +} diff --git a/src/sam.c b/src/sam.c index 2334bdd2..9865e505 100644 --- a/src/sam.c +++ b/src/sam.c @@ -93,7 +93,12 @@ void Init() bufferpos = 0; // TODO, check for free the memory, 10 seconds of output should be more than enough buffer = malloc(22050*10); - + if(NULL==buffer) // AF + { + printf("Not enough memory to allocate 220500 bytes\n"); + exit(1); + } + memset(buffer,128,22050*10); //AF: avoid "hiss" at the end of sound playback /* freq2data = &mem[45136]; freq1data = &mem[45056];