Habla dígitos del 0 al 9 en voz alta

15

Inspirado por esta pregunta de electronics.SE , aquí hay un desafío para ti:

Escriba un programa o subrutina que tome una secuencia de dígitos decimales (0 a 9) y los hable en voz alta, sin usar una herramienta de síntesis de voz existente.

Entrada:

Puede solicitar que los dígitos de entrada se proporcionen en cualquier formato razonable, por ejemplo, como una cadena de dígitos ASCII, una matriz de enteros, un número codificado en BCD, etc. Si su solución es un programa ejecutable, puede tomar la entrada como un parámetro de línea de comando, léalo desde la entrada estándar u obténgalo de cualquier otra manera razonable.

Su programa debe poder hablar al menos ocho dígitos por invocación. Usted puede asumir que el primer dígito no es cero, a menos que sea el único dígito.

Salida:

Su programa puede decir los números directamente usando un dispositivo de audio o puede generar un archivo de sonido reproducible. El archivo de salida, si lo hay, puede estar en cualquier formato de audio estándar o puede consistir en datos de muestra sin procesar. Si emite datos de muestra sin procesar, tenga en cuenta los parámetros apropiados para la reproducción (frecuencia de muestreo, bits por muestra, endianness, con signo / sin signo, número de canales). Se prefieren los formatos admitidos por aplay .

Usted es libre de decidir los detalles sobre cómo se hablarán los números, pero su salida debe consistir en dígitos del idioma inglés hablados de manera comprensible para un hablante típico de inglés , y debe ser lo suficientemente claro para que el oyente pueda transcribir con precisión un número aleatorio hablado de ocho dígitos. No, solo pitar n veces no cuenta. No olvide incluir pausas entre los dígitos.

Puntuación:

Se aplican reglas estándar puntuación de : su puntuación es la longitud de su código en bytes o, si su código está escrito en texto Unicode, en caracteres Unicode. La puntuación más baja gana. Cualquier idioma vale.

Como la pregunta original sobre electrónica.SE era sobre programación incrustada, sentí que sería apropiado lanzar un hueso a los autores que usan lenguajes de bajo nivel: si su solución está escrita en un lenguaje compilado, puede elegir contar la longitud del archivo ejecutable compilado en bytes como su puntaje. (Sí, el código de bytes precompilado, como un .classarchivo Java , también está bien.) Si elige hacer uso de esta opción, incluya una copia del ejecutable compilado en su respuesta (por ejemplo, como un volcado hexadecimal) junto con su código fuente y la versión del compilador y las opciones que usó para generarlo.

Se otorgará una mención de honor , junto con una recompensa de +50 repeticiones, a la primera respuesta que también cumpla con los criterios de la pregunta original , es decir, es capaz de ejecutarse en una MCU integrada con 4 kb de flash y 1 kb de SRAM.

Restricciones:

No puede hacer uso de ningún archivo o recurso de red que no forme parte del entorno de tiempo de ejecución estándar de su idioma elegido, a menos que cuente la longitud de dichos archivos o recursos como parte de su puntaje. (Esto es para no permitir, por ejemplo, cargar muestras de audio desde la web).

Tampoco puede usar ninguna herramienta de síntesis de voz o bibliotecas preexistentes o compilaciones de datos de audio (a menos que también cuente su tamaño como parte de su puntaje), incluso si están incluidos en el entorno de tiempo de ejecución estándar del idioma elegido.

Ilmari Karonen
fuente
PD. Puedo publicar una solución propia más tarde, si logro que produzca algo que realmente suene comprensible. Sin embargo, no tengas miedo de publicar el tuyo; En este punto, cualquier respuesta es una buena respuesta.
Ilmari Karonen
1
¿Se nos permite descargar una base de datos de dígitos hablados (y contar su tamaño para la partitura) o tenemos que grabar nuestra propia voz? Dudo que pueda generar muestras de voz algorítmicamente.
John Dvorak
umm ... la sección "salida" no especifica que debemos generar muestras de voz. ¿Se nos permite simplemente emitir un pitido diez veces?
John Dvorak
@PeterTaylor: si cuenta su tamaño como parte de su puntaje, está bien. Me preocupaba que pudiera haber algún sistema que tuviera muestras de audio de dígitos enterrados en algún lugar en su entorno de tiempo de ejecución estándar.
Ilmari Karonen
3
Dado que parece haber un flujo constante de personas que no leen la pregunta hasta el final y publican envoltorios triviales en bibliotecas de gran peso, puede valer la pena editar para poner aún más énfasis en el aspecto "Hágalo usted mismo".
Peter Taylor

Respuestas:

10

ruby - 3710 = código de 90 caracteres + datos de 3620 bytes

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

input: un argumento de línea de comando único, el número a leer

salida: datos de sonido sin procesar, PCM 8bit / 8kHz

Esto puede leer cualquier cadena de entrada, siempre que

  • solo contiene caracteres que son nombres de archivo válidos. por solo cuatro caracteres, puede ampliar ese conjunto a todos los personajes.
  • Tienes los archivos necesarios.
  • ¿por qué oh, tú, espacio, oh, en, apóstrofe, tee, espacio, em, en, dee, espacio, camiseta, a

5e3codifica la pausa entre dos palabras. Aquí, 5kmuestras ~ = 0.6s. Ajustar según lo deseado.

Ahora, la parte difícil es obtener los archivos de muestra en 4K y aún así poder descomprimirlos fácilmente y con suficiente calidad. Así es como los obtuve:

  • Tome un motor de texto a voz capaz de producir archivos de sonido. Wikipedia tiene uno .
  • Aliméntelo con un texto que contenga todos los dígitos, idealmente juntos. Usé http://en.wikipedia.org/wiki/Base_13
  • Downsample
  • Recorta cada parte en un editor de sonido .
  • Guardar como un archivo sin formato.
  • Diezmar cada muestra (descartar bits de bajo orden).
  • Desinflar.

Ahora, uno tiene que elegir una frecuencia de muestreo y una cantidad de diezmos. Demasiado, y el sonido no será comprensible. Demasiado poco, y no encajas. Me he conformado con 8kHz / 3b. Ahí están: https://github.com/honnza/drops/raw/master/digits.zip

  • 8KHz * 4b / muestra y mayor calidad - demasiado grande
  • 8KHz * 3b / muestra: baja calidad, pero se ajusta a 4K
  • 8KHz * 2b / muestra - kch kchhhhhhhhh [no comprensible]
  • 2KHz * 8b / muestra - demasiado grande
  • 2KHz * 3b / muestra - kch kchhhhhhhhh
  • 1KHz * 8b / muestra - kch kchhhhhhhhh

Aquí está el script de diezmado:

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

En cuanto al desafío original: hay 476 bytes de espacio para el código y la tabla de archivos. Esto podría ser un poco demasiado dependiendo de cuán pequeño podamos ser con una biblioteca DEFLATE. Si es necesario, podemos cortar algunas esquinas aquí y allá recortando las muestras de audio un poco más agresivamente. [fo:r]o [o:]realmente no importa, pero ahorra bytes. He sido algo benevolente al recortar los números. Además, un esquema de diezmado diferente o sacrificar un poco de diezmado para reducir la toma de muestras podría ayudar, voy a jugar con esto más adelante. Además, soltar los encabezados DEFLATE puede ahorrar una pequeña cantidad de espacio.

Concatenar muestras de sonido es bastante fácil, pero 4K es un poco estrecho. Si no está limitado por un espacio de 4k, sugiero menos diezmado. A 4 bits por muestra en realidad le va bastante bien y es solo un poco más grande.

John Dvorak
fuente
+1, no está mal. Sin embargo, la claridad es bastante marginal: intenté transcribir algunos números aleatorios y obtuve una tasa de éxito de aproximadamente el 70%. (Esperaba algo más cercano al 99%.) También estoy un poco indeciso con respecto a la mención de honor: si bien has argumentado bastante bien que 4K podría alcanzarse de esta manera, no lo has hecho De hecho lo demostró. Incluso si abandonaste Ruby para C (lo que parece bastante fácil de hacer; estaría dispuesto a tomar esa parte con fe), ¿ realmente podrías colocar un decodificador DEFLATE en el espacio flash restante? Además, como señalé, la calidad del sonido es bastante mala.
Ilmari Karonen
PD. Algunos consejos sobre una mejor compresión: puede rellenar todas las muestras a una longitud fija con bytes nulos (que deberían comprimirse bien) y concatenarlas en un archivo comprimido, luego descomprimirlas y cortarlas. Además, el truco KZIP de esta respuesta podría darte una mejor compresión DEFLATE. Finalmente, intente editar el archivo de sonido combinado para reemplazar fonemas equivalentes con copias exactas.
Ilmari Karonen
bueno, las muestras de sonido originales tampoco eran exactamente comprensibles en mi opinión: el muestreo disminuyó poco el daño. La biblioteca DEFLATE más pequeña que conozco, la primera vinculada por wikipeda, pesa alrededor de 500b. Francamente, ¿quieres que porte el inflador a ese dispositivo específico? Podría llegar a eso en realidad, pero nunca antes había codificado ARM.
John Dvorak
Estoy bastante sorprendido por la tasa de éxito del 70%: he descubierto que los números son fáciles de entender. ¿Qué dígitos confundiste más?
John Dvorak
Portarlo a un Cortex M0 es probablemente un poco demasiado pedir (aunque si se pudiera hacer eso, eso sería increíble!), Pero sí creo que un binario independiente (archivos + datos, si los hay) Instalación debajo 4k parecería una demostración razonable. (No es necesario vincular estáticamente en libc para E / S de archivo, ya que no lo necesitaría en un dispositivo incrustado, pero el código DEFLATE ciertamente debería contarse). Básicamente, algo que podría publicar como respuesta a la pregunta original en electrónica. SE y digan con confianza "si compila esto para su dispositivo, apuesto a que encajará".
Ilmari Karonen