Wypowiadaj na głos cyfry od 0 do 9

15

Zainspirowany tym pytaniem z Electronics.SE , oto wyzwanie dla Ciebie:

Napisz program lub podprogram, który pobiera ciąg cyfr dziesiętnych (od 0 do 9) i wypowiada je na głos, bez użycia istniejącego narzędzia do syntezy mowy.

Wejście:

Możesz poprosić o podanie cyfr wejściowych w dowolnym rozsądnym formacie, np. Jako ciąg cyfr ASCII, tablica liczb całkowitych, liczba zakodowana w BCD itp. Jeśli twoje rozwiązanie jest programem wykonywalnym, możesz wziąć dane wejściowe jako parametr wiersza poleceń, przeczytaj go ze standardowego wejścia lub uzyskaj w inny rozsądny sposób.

Twój program musi umieć wymawiać co najmniej osiem cyfr na każde wywołanie. Państwo może zakładać, że pierwsza cyfra nie jest zero, chyba że jest to tylko cyfra.

Wynik:

Twój program może wymawiać liczby bezpośrednio za pomocą urządzenia audio lub może odtwarzać odtwarzany plik dźwiękowy. Plik wyjściowy, jeśli istnieje, może być w dowolnym standardowym formacie audio lub może składać się z surowych próbek danych. Jeśli wyprowadzasz surowe dane przykładowe, zwróć uwagę na odpowiednie parametry do odtwarzania (częstotliwość próbkowania, liczba bitów na próbkę, endianness, podpisany / niepodpisany, liczba kanałów). Preferowane są formaty obsługiwane przez aplikację .

Możesz swobodnie decydować o szczegółach, w jaki sposób będą wypowiadane liczby, ale twój wynik powinien składać się z cyfr w języku angielskim wymawianych w sposób zrozumiały dla typowego anglojęzycznego i powinno być wystarczająco jasne, aby słuchacz mógł dokładnie transkrybować ośmiocyfrowa liczba mówiona. Nie, tylko dźwięk n razy się nie liczy. Nie zapomnij uwzględnić pauz między cyframi.

Punktacja:

Obowiązują standardowe reguły oceniania : Twój wynik to długość kodu w bajtach lub, jeśli kod jest napisany tekstem Unicode, znakami Unicode. Najniższy wynik wygrywa. Dowolny język.

Ponieważ pierwotne pytanie na temat elektroniki. SE dotyczyło programowania wbudowanego, uznałem, że należałoby rzucić kość autorom używającym języków niskiego poziomu: jeśli twoje rozwiązanie jest napisane w języku skompilowanym, możesz policzyć długość skompilowany plik wykonywalny w bajtach jako wynik. (Tak, prekompilowany kod bajtowy, taki jak .classplik Java , również jest OK.) Jeśli zdecydujesz się skorzystać z tej opcji, dołącz do swojej kopii kopię skompilowanego pliku wykonywalnego (np. Zrzut heksadecymalny) wraz z kodem źródłowym oraz wersję kompilatora i opcje użyte do jej wygenerowania.

Wyróżnienie , wraz z bounty +50 rep, zostaną przyznane pierwszej odpowiedzi, które również spełnia kryteria oryginalne pytanie , to znaczy jest w stanie działać na osadzonym MCU z 4 KB Flash i 1 kb SRAM.

Ograniczenia:

Nie możesz korzystać z plików lub zasobów sieciowych , które nie są częścią standardowego środowiska uruchomieniowego wybranego przez Ciebie języka, chyba że uwzględnisz długość tych plików lub zasobów jako część wyniku. (Ma to na celu uniemożliwić np. Ładowanie próbek audio z Internetu).

Nie możesz również używać żadnych wcześniej istniejących narzędzi do syntezy mowy, bibliotek lub kompilacji danych audio (chyba że uwzględnisz ich rozmiar jako część wyniku), nawet jeśli są one zawarte w standardowym środowisku uruchomieniowym wybranego języka.

Ilmari Karonen
źródło
Ps. Mogę opublikować własne rozwiązanie później, jeśli uda mi się sprawić, że stworzy coś, co w rzeczywistości brzmi zrozumiale. Nie wstydź się jednak publikować własnych; w tym momencie każda odpowiedź jest dobrą odpowiedzią.
Ilmari Karonen
1
Czy możemy pobrać bazę danych mówionych (i policzyć jej wielkość w stosunku do wyniku), czy też musimy nagrać własny głos? Wątpię, czy potrafię algorytmicznie generować próbki mowy.
John Dvorak
umm ... sekcja „wyjściowa” nie określa, że ​​musimy wyprowadzać próbki mowy. Czy wolno nam po prostu wydać dźwięk dziesięć razy?
John Dvorak
@PeterTaylor: Jeśli policzysz ich rozmiar jako część swojego wyniku, to jest OK. Martwiłem się tylko, że może istnieć jakiś system, w którym gdzieś w jego standardowym środowisku wykonawczym są zakopane próbki cyfr.
Ilmari Karonen
3
Ponieważ wydaje się, że istnieje stały strumień ludzi, którzy nie czytają pytania do końca i publikują trywialne opakowania w bibliotekach wagi ciężkiej, warto by je edytować, aby jeszcze bardziej podkreślić aspekt „zrób to sam”.
Peter Taylor,

Odpowiedzi:

10

ruby - 3710 = kod 90 znaków + dane 3620 bajtów

require'zlib'
$><<$*[0].chars.map{|x|Zlib::Inflate.inflate File.open(x).read}.join(?0*5e3)

input: pojedynczy argument wiersza poleceń, liczba do odczytania

wyjście: surowe dane dźwiękowe, PCM 8bit / 8kHz

Może to odczytać dowolny ciąg wejściowy, o ile

  • zawiera tylko znaki, które są prawidłowymi nazwami plików. tylko dla czterech znaków, możesz powiększyć ten zestaw do wszystkich znaków.
  • masz niezbędne pliki.
  • dlaczego oh you space dee oh en apostrophe tee space em i en dee space tee aitch is es period

5e3koduje pauzę między dwoma słowami. Tutaj 5 próbek ~ = 0,6s. Dostosuj według potrzeb.

Teraz trudną rzeczą jest uzyskanie przykładowych plików w rozdzielczości 4K, a jednocześnie możliwość ich łatwej dekompresji i odpowiedniej jakości. Oto jak je dostałem:

  • Weź silnik zamiany tekstu na mowę zdolny do tworzenia plików dźwiękowych. Wikipedia ma jeden .
  • Podaj tekst zawierający wszystkie cyfry, najlepiej blisko siebie. Użyłem http://en.wikipedia.org/wiki/Base_13
  • Próbkowanie w dół.
  • Wytnij każdą część w edytorze dźwięku .
  • Zapisz jako plik surowy.
  • Zdziesiątkuj każdą próbkę (odrzuć bity niskiego rzędu).
  • Siadać.

Teraz trzeba wybrać częstotliwość próbkowania i kwotę dziesiętną. Za dużo, a dźwięk nie będzie zrozumiały. Za mało, a ty nie pasujesz. Postawiłem na 8kHz / 3b. Oto one: https://github.com/honnza/drops/raw/master/digits.zip

  • 8 KHz * 4b / próbka i wyższa jakość - za duża
  • 8 KHz * 3b / próbka - niska jakość, ale pasuje do 4K
  • 8 KHz * 2b / próbka - kch kchhhhhhhh [niezrozumiałe]
  • 2 KHz * 8b / próbka - za duża
  • 2 KHz * 3b / próbka - kch kchhhhhhhhh
  • 1 KHz * 8b / próbka - kch kchhhhhhhhh

Oto skrypt dziesiętny:

require'zlib'
Dir.glob "*.raw" do |fname|
  File.open fname[/\d/], "wb" do |out|
    File.open fname do |input|
      bytes = input.bytes.to_a
      bytes.map! {|x|x&0xE0}
      dfl = Zlib::Deflate.deflate(bytes.pack("C*"),9)
      dfl.each_byte do |byte|
        out.print byte.chr
      end
      puts "done #{fname}: #{dfl.size}"
    end
  end
end

Jeśli chodzi o oryginalne wyzwanie: jest 476 bajtów miejsca na kod i tablicę plików. Może to być nieco za dużo w zależności od tego, jak małe możemy uzyskać dzięki bibliotece DEFLATE. W razie potrzeby możemy wyciąć kilka rogów tu i tam, przycinając próbki audio nieco bardziej agresywnie. [fo:r]lub [o:]tak naprawdę nie ma znaczenia, ale oszczędza bajty. Byłem nieco życzliwy, kiedy przycinałem liczby. Pomocny może być również inny schemat dziesiętny lub poświęcenie części dziesiętnej dla próbkowania w dół - później się z nimi bawię. Ponadto upuszczenie nagłówków DEFLATE może zaoszczędzić niewielką ilość miejsca.

Łączenie próbek dźwięku jest dość łatwe, ale 4K jest trochę ciasne. Jeśli nie jesteś związany przestrzenią 4k, sugeruję mniejsze zdziesiątkowanie. 4 bity na próbkę faktycznie wypadają całkiem dobrze i są tylko nieznacznie większe.

John Dvorak
źródło
+1, nieźle. Jasność jest jednak marginalna: próbowałem przepisać kilka liczb losowych i osiągnąłem wskaźnik sukcesu około 70%. (Miałem nadzieję na coś zbliżonego do 99%). Nadal jestem trochę na przeszkodzie w kwestii wyróżnienia: chociaż dobrze argumentowałeś, że 4K można osiągnąć w ten sposób, nie zrobiłeś tego faktycznie to zademonstrowałem. Nawet jeśli porzuciłeś rubin dla C (co wydaje się dość łatwe; chętnie wezmę tę rolę z wiarą), czy naprawdę mógłbyś umieścić dekoder DEFLATE w pozostałej przestrzeni flash? Dodatkowo, jak zauważyłem, jakość dźwięku jest dość zła.
Ilmari Karonen
Ps. Kilka wskazówek na temat lepszej kompresji: Możesz wypełnić wszystkie próbki do ustalonej długości zerowymi bajtami (które powinny dobrze się kompresować) i połączyć je w jeden skompresowany plik, a następnie rozpakować i pokroić. Ponadto sztuczka KZIP z tej odpowiedzi może zapewnić lepszą kompresję DEFLATE. Na koniec spróbuj edytować połączony plik dźwiękowy, aby zastąpić równoważne fonemy dokładnymi kopiami.
Ilmari Karonen
cóż, oryginalne próbki dźwięku nie były do ​​końca zrozumiałe dla IMO - próbkowanie w dół nie spowodowało tego zbyt wiele. Najmniejsza biblioteka DEFLATE, którą znam - pierwsza z linkowanych przez wikipeda - waży około 500b. Szczerze mówiąc, czy chcesz, żebym przeniósł inflator na to konkretne urządzenie? Mogę do tego dojść, ale nigdy wcześniej nie kodowałem ARM.
John Dvorak,
Jestem zaskoczony 70% wskaźnikiem sukcesu - liczby te są łatwe do zrozumienia. Które cyfry najbardziej pomyliłeś?
John Dvorak,
Przeniesienie go do Cortexa M0 to chyba trochę za dużo (choć gdybyś mógł to zrobić, to byłoby niesamowite!), Ale myślę, że samodzielny plik binarny (+ pliki danych, jeśli w ogóle) pasuje pod 4k wydaje się rozsądną demonstracją. (Nie ma potrzeby statycznego linkowania w libc do We / Wy pliku, ponieważ nie byłoby to potrzebne na urządzeniu osadzonym, ale kod DEFLATE z pewnością powinien zostać policzony.) Zasadniczo coś, co można opublikować jako odpowiedź na pierwotne pytanie na Electronics.SE i śmiało powiedzieć „jeśli skompilujesz to dla swojego urządzenia, założę się, że będzie pasować”.
Ilmari Karonen