Spanish Crear archivo de audio a partir de un texto?

punteral

Member
Hola a todos.


Me gustaría conseguir que al escribir un texto en un EditText y pulsar un botón se cree un archivo de sonido diciendo lo que pone en el texto.

Ya he conseguido que al pulsar el botón se reproduzca la voz leyendo el texto mediante la utilización de la librería TTS.

B4X:
Sub Button1_Click
     TTS1.Speak(EditText1.Text, True)
End Sub

¿Pero alguien sabe como conseguir el archivo de sonido que se reproduce para poder trabajar posteriormente con él?


Muchas gracias por adelantando.
Saludos.
 
Last edited:

Descartex

Well-Known Member
Licensed User
Longtime User
Buenas!!!
Echale un ojo a esta solucion de Erel.
Un saludo.
 

TILogistic

Expert
Licensed User
Longtime User

punteral

Member

Lo primero muchísimas gracias por contestar.

Tal y como comenta Erel en el hilo que has enlazado se puede grabar el sonido con el micrófono del teléfono cuando se reproduce el archivo de sonido por el altavoz.


VENTAJAS:

1. Por desgracia es la única manera que he encontrado de obtener el archivo de audio a partir de un texto.


DESVENTAJAS:

1. Al ser una grabación la calidad no es muy buena y se escucha ruido de fondo

2. No he conseguido que el proceso se realice automáticamente, por lo que tenemos que ser nosotros mismos los que iniciemos y finalicemos la grabación mediante botones.


Expongo aquí mi código y algunas observaciones por si a alguien le sirve de ayuda y por si alguien quiere revisarlo o mejorarlo.

B4X:
#Region  Project Attributes
    #ApplicationLabel: B4A 1
    #VersionCode: 1
    #VersionName:
    'SupportedOrientations possible values: unspecified, landscape or portrait.
    #SupportedOrientations: unspecified
    #CanInstallToExternalStorage: False
#End Region

#Region  Activity Attributes
    #FullScreen: False
    #IncludeTitle: True
#End Region

Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.
    
    Dim TTS1 As TTS
    
    Private streamer As AudioStreamer
    Private buffers As List
    Private timer1 As Timer
    Private recordingStart As Long
    Private output As OutputStream
    Private recording As Boolean
    Private mBitRate As Int = 16
    Private mSampleRate As Int = 22050
    Private mMono As Boolean = True
    Private mFileName As String = "1.wav"
    Private mp As MediaPlayer
    Private rp As RuntimePermissions

End Sub

Sub Globals
    Dim Label1 As Label
    Dim btnPlay As Button
    Dim btnStartRecording As Button
    Dim btn_leer_texto As Button
    Dim EditText1 As EditText
    Dim spnrLanguages As Spinner
End Sub

Sub Activity_Create(FirstTime As Boolean)
    Activity.LoadLayout("1")
    
    'shared = rp.GetSafeDirDefaultExternal("")
    'Dim testFolder As String = rp.GetSafeDirDefaultExternal("test")
    'File.WriteString(testFolder, "test.txt","aaa")
    rp.CheckAndRequest(rp.PERMISSION_WRITE_EXTERNAL_STORAGE)
    rp.CheckAndRequest(rp.PERMISSION_RECORD_AUDIO)
    Wait for activity_permissionResult (Permission As String, result As Boolean)

    spnrLanguages.AddAll(Array As String("en", "fr", "de","spa"))
    TTS1.Initialize("TTS1")

    If FirstTime Then
        streamer.Initialize("streamer", mSampleRate, mMono, mBitRate, streamer.VOLUME_MUSIC)
        buffers.Initialize
        timer1.Initialize("timer1", 1000)
        mp.Initialize2("mp")
    End If
End Sub

'Botón para leer el texto que hayamos escrito
Sub btn_leer_texto_Click
    
    TTS1.Speak(EditText1.Text, True)

End Sub

'Selector de idioma
Sub spnrLanguages_ItemClick (Position As Int, Value As Object)
    If TTS1.SetLanguage(Value, "") = False Then
        ToastMessageShow("Language data not found.", True)
        Return
    End If
End Sub

Sub StartWaveFile(Dir As String, FileName As String, SampleRate As Int, Mono As Boolean _
        , BitsPerSample As Int) As OutputStream
    File.Delete(Dir, FileName)
    Dim raf As RandomAccessFile
    raf.Initialize2(Dir, FileName, False, True)
    raf.WriteBytes("RIFF".GetBytes("ASCII"), 0, 4, raf.CurrentPosition)
    raf.CurrentPosition = 8 'skip 4 bytes for the size
    raf.WriteBytes("WAVE".GetBytes("ASCII"),0, 4, raf.CurrentPosition)
    raf.WriteBytes("fmt ".GetBytes("ASCII"),0, 4, raf.CurrentPosition)
    raf.WriteInt(16, raf.CurrentPosition)
    raf.WriteShort(1, raf.CurrentPosition)
    Dim numberOfChannels As Int
    If Mono Then numberOfChannels = 1 Else numberOfChannels = 2
    raf.WriteShort(numberOfChannels, raf.CurrentPosition)
    raf.WriteInt(SampleRate, raf.CurrentPosition)
    raf.WriteInt(SampleRate * numberOfChannels * BitsPerSample / 8, raf.CurrentPosition)
    raf.WriteShort(numberOfChannels * BitsPerSample / 8, raf.CurrentPosition)
    raf.WriteShort(BitsPerSample, raf.CurrentPosition)
    raf.WriteBytes("data".GetBytes("ASCII"),0, 4, raf.CurrentPosition)
    raf.WriteInt(0, raf.CurrentPosition)
    raf.Close
    Return File.OpenOutput(Dir, FileName, True)
End Sub

Sub CloseWaveFile(Dir As String, FileName As String)
    Dim raf As RandomAccessFile
    raf.Initialize2(Dir, FileName, False, True)
    raf.WriteInt(raf.Size - 8, 4)
    raf.WriteInt(raf.Size - 44, 40)
    raf.Close
End Sub

Sub streamer_RecordBuffer (Buffer() As Byte)
    If recording Then output.WriteBytes(Buffer, 0, Buffer.Length)
    'the above check is required as the last message will arrive after we call StopRecording.
End Sub

'Botón para iniciar la grabación
Sub btnStartRecording_Click
    buffers.Clear
    output = StartWaveFile(File.DirRootExternal, mFileName, mSampleRate, mMono, mBitRate)
    recording = True
    streamer.StartRecording
    recordingStart = DateTime.Now
    timer1.Enabled = True
    Timer1_Tick
    btnPlay.Enabled = False
End Sub

Sub Timer1_Tick
    Label1.Text = "Recording: " & _
        Round((DateTime.Now - recordingStart) / DateTime.TicksPerSecond) & " seconds"
End Sub

'Botón para detener la grabación
Sub btnStopRecording_Click
    streamer.StopRecording
    recording = False
    output.Close
    CloseWaveFile(File.DirRootExternal, mFileName)
    timer1.Enabled = False
    btnPlay.Enabled = True
    Label1.Text = ""
End Sub

'Botón para reproducir lo que hemos grabado
Sub btnPlay_Click
    mp.Load(File.DirRootExternal, mFileName)
    mp.Play
End Sub

Sub mp_Complete
    Log("PlaybackComplete")
    btnStartRecording.Enabled = True
End Sub


Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub


OBSERVACIONES


- La aplicación consta de lo siguiente:

Un EditText para escribir el texto que queremos pasar a voz

Un botón LEER que reproduce una voz leyendo el texto

Un selector para indicar el idioma en el que queremos la voz

Un botón para empezar a grabar

Un botón para terminar de grabar

Un botón para reproducir lo que hemos grabado


- El archivo se crea con el nombre 1.wav en el almacenamiento interno del móvil


- En el código se incluye la solicitud de los permisos necesarios par que funciones

Permiso para acceder al almacenamiento interno del móvil

Permiso para grabar sonido con el micrófono


SIGUIENTE PASO:

Encontrar la manera de que el proceso de grabación se realice automáticamente. Si alguien tiene alguna indicación para resolverlo se lo agradecemos yo y los que se encuentren este mismo problema en el futuro y consulten este hilo. Intentaré ir exponiendo aquí todos los avances que consiga.


Muchas gracias otra vez y un saludo.
 

punteral

Member

Muchísimas gracias por contestar. He estado investigando la solución que se propone en ese hilo, pero creo que me faltan los conocimientos necesarios para aplicarla.

B4X:
Sub tts1_Ready (Success As Boolean)
    Log(Success)
    Dim jo As JavaObject = TTS1
    Dim m As JavaObject
    m.InitializeNewInstance("java.util.HashMap", Null)
    jo.RunMethod("synthesizeToFile", Array("a b c", m, File.Combine(File.DirRootExternal, "2.wav")))
End Sub

¿Cómo puedo relacionar este código con el EditText donde está el texto que quiero pasar a voz?

Gracias por adelantado.
Saludos.
 

TILogistic

Expert
Licensed User
Longtime User
Depend:

TTS
JavaObject

B4X:
SaveTextToTTSFile(TTS1, "HELLO", File.DirRootExternal, "Chat.wav")

Sub SaveTextToTTSFile(SpeechInput As TTS, Text As String, Directory As String, FileName As String)
    Dim jo As JavaObject = SpeechInput
    Dim m As JavaObject
    m.InitializeNewInstance("java.util.HashMap", Null)
    jo.RunMethod("synthesizeToFile", Array(Text, m, File.Combine(Directory, FileName)))
End Sub
 
Last edited:

punteral

Member
Muchísimas gracias por responder oparra.

He intentado ejecutar el código que has indicado mediante un botón, pero al pulsarlo en la App no se crea ningún archivo.

He agregado al código la solicitud de permisos PERMISSION_WRITE_EXTERNAL_STORAGE, pero sigue sin crearse el archivo.

No aparece ningún mensaje de error, simplemente no se crea el archivo al pulsar el botón que ejecuta el código que me has indicado. ¿Hay algo que se me ha pasado? Seguro que sí, si alguien puede darme alguna indicación se lo agradezco.

Adjunto el código.

B4X:
#Region  Project Attributes
    #ApplicationLabel: B4A synth
    #VersionCode: 1
    #VersionName:
    'SupportedOrientations possible values: unspecified, landscape or portrait.
    #SupportedOrientations: unspecified
    #CanInstallToExternalStorage: False
#End Region

#Region  Activity Attributes
    #FullScreen: False
    #IncludeTitle: True
#End Region

Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.
    Dim TTS1 As TTS
    Private rp As RuntimePermissions
    
End Sub

Sub Globals
    'These global variables will be redeclared each time the activity is created.
    'These variables can only be accessed from this module.

    Dim btn_leer_texto As Button
End Sub

Sub Activity_Create(FirstTime As Boolean)
    'Do not forget to load the layout file created with the visual designer. For example:
    'Activity.LoadLayout("Layout1")
    Activity.LoadLayout("layout1")
    
    rp.CheckAndRequest(rp.PERMISSION_WRITE_EXTERNAL_STORAGE)
    Wait for activity_permissionResult (Permission As String, result As Boolean)

    TTS1.Initialize("TTS1")
End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub



Sub SaveTextToTTSFile(SpeechInput As TTS, Text As String, Directory As String, FileName As String)
    Dim jo As JavaObject = SpeechInput
    Dim m As JavaObject
    m.InitializeNewInstance("java.util.HashMap", Null)
    jo.RunMethod("synthesizeToFile", Array(Text, m, File.Combine(Directory, FileName)))
End Sub

Sub btn_leer_texto_Click
    
    SaveTextToTTSFile(TTS1, "HELLO", File.DirRootExternal, "Chat.wav")
    
End Sub


Muchas gracias otra vez.
Saludos.
 

josejad

Expert
Licensed User
Longtime User
Hola:

He probado tu ejemplo y funciona. Dónde estás buscando el archivo wav? Ahora mismo lo estás poniendo en el raíz de la memoria.
Revisa el tutorial:

Si te fijas, recomienda no usar File.DirRootExternal

1. Use RuntimePermissions.GetSafeDirDefaultExternal("") instead of File.DirDefaultExternal. The parameter passed is an optional subfolder that will be created under the default folder.

Prueba a poner mejor:
rp..GetSafeDirDefaultExternal("tu_carpeta") y haz un
B4X:
Log(rp..GetSafeDirDefaultExternal("tu_carpeta"))

para que te diga donde buscar.

saludos,
 

Attachments

  • audio.zip
    9.4 KB · Views: 286

electronicajaf

Member
Licensed User
Longtime User
Buen Día, soy Juan, Tengo una aplicación en la que al llegar un mensaje de texto, mail o WathsApp me los lee en vos alta, es esto lo que buscas?
Avisame y lo subo...
Saludos
Juan
 
Cookies are required to use this site. You must accept them to continue using the site. Learn more…