Eseguire un file audio

Forum dedicato ai programmatori di X# in lingua italiana – Italian language forum

Moderator: wriedmann

Post Reply
User avatar
claudiocarletta
Posts: 101
Joined: Sat Sep 05, 2020 8:56 am

Eseguire un file audio

Post by claudiocarletta »

Salve a tutti,
ho la necessità di allertare gli utenti con un messaggio sonoro (file audio) al verificarsi di un evento sul database MySQL. L'applicazione potrebbe essere iconizzata o addirittura non presidiata (l'utente potrebbe essere occupato nell'ufficio adiacente)
C'è un modo per "eseguire" un file audio in background?
Pensavo di utilizzare

Code: Select all

SELF:RegisterTimer(30, false) 
per eseguire ogni 30 secondi il

Code: Select all

METHOD Timer()
per controllare il database e nell'eventualità ci fosse bisogno dell'intervento dell'operatore eseguire il file audio per richiamare l'attenzione dell'operatore.
Vi ricordo che adopero X# nel dialetto VO

Grazie a tutti
Claudio
User avatar
softdevo@tiscali.it
Posts: 191
Joined: Wed Sep 30, 2015 1:30 pm

Eseguire un file audio

Post by softdevo@tiscali.it »

Puoi usare la classe System.Speech.Synthesis.SpeechSynthesizer che ti permette di far parlare il tuo PC facendogli "leggere" una qualsiasi stringa con la velocità ed il volume che vuoi.
Ho estratto da una mia applicazione quello che serve,spero di aver messo tutto, contattami se ho dimenticato qualcosa.

Danilo

FUNCTION Parla(cTesto AS STRING) AS VOID
LOCAL _Lettura AS Lettura
_Lettura := Lettura{}
_Lettura:ImpostaVoce()
_Lettura:Voce(cTesto,TRUE)
_Lettura:ChiudiParlato()
RETURN

CLASS Lettura
EXPORT oVoce AS System.Speech.Synthesis.SpeechSynthesizer
EXPORT Nome_SV AS STRING
EXPORT nVolume AS INT
EXPORT nRate AS INT
EXPORT Nome AS STRING
EXPORT Attivo AS STRING
METHOD ImpostaVoce() AS VOID
LOCAL oXMLFile AS XML_File
LOCAL cVolume,cRate AS STRING
/*
Microsoft Elsa Desktop - Italian (Italy)
Microsoft Zira Desktop - English (United States)
ScanSoft Silvia_Dri40_16kHz
*/
SELF:Nome_SV := "Microsoft Elsa Desktop" //"ScanSoft Silvia_Dri40_16kHz"
SELF:nVolume := 100
SELF:nRate := -3

IF File(WorkDir()+"parla.xml")
oXMLFile := XML_File{WorkDir()+"parla.xml"}
IF oXMLFile:ExistSection("SET")
SELF:Nome_SV := iif(!Empty(oXMLFile:GetEntry("SET","NOME")),oXMLFile:GetEntry("SET","NOME"),"ScanSoft Silvia_Dri40_16kHz")
cVolume := iif(!Empty(oXMLFile:GetEntry("SET","VOLUME")),oXMLFile:GetEntry("SET","VOLUME"),"30")
SELF:nVolume := Val(cVolume)
cRate := iif(!Empty(oXMLFile:GetEntry("SET","RATE")),oXMLFile:GetEntry("SET","RATE"),"-3")
SELF:nRate := Val(cRate)
IF SELF:nRate > 10
SELF:nRate := 10
ENDIF
IF SELF:nRate < -10
SELF:nRate := -10
ENDIF
ENDIF
ENDIF

IF !Empty(SELF:Nome_SV) //Contiene il nome della Dll
SELF:oVoce := System.Speech.Synthesis.SpeechSynthesizer{}
SELF:oVoce:SelectVoice(SELF:Nome_SV) //Self:Nome_SV
SELF:oVoce:SelectVoiceByHints(System.Speech.Synthesis.VoiceGender.Female , System.Speech.Synthesis.VoiceAge.Adult)
SELF:oVoce:Rate := SELF:nRate
SELF:oVoce:Volume := SELF:nVolume //contiene il valore della variabile Self:nVolume: 0=nessun volume 30=medio basso
// Voce("benvenuti nel programma di gestione del parlato",TRUE)
ELSE
SELF:oVoce := NULL_OBJECT
ENDIF

RETURN
METHOD ScriviImpostaVoce() AS VOID
LOCAL oXMLFile AS XML_File
LOCAL oStream AS System.IO.StreamWriter
LOCAL cTesto AS STRING
LOCAL cSpazi AS STRING

IF File(WorkDir()+"parla.xml")
oXMLFile := XML_File{WorkDir()+"parla.xml"}
oXMLFile:WriteEntry( "SET", "NOME",SELF:Nome_SV)
oXMLFile:WriteEntry( "SET", "VOLUME",NTrim(SELF:nVolume))
oXMLFile:WriteEntry( "SET", "RATE",NTrim(SELF:nRate))
//oXMLFile:WriteEntry( "SET", "LINGUA",SELF:Lingua)
oXMLFile:WriteEntry( "SET", "ATTIVO",SELF:Attivo)
oXMLFile:Close()
ELSE
cSpazi := Space(2)
cTesto := "<?xml version='1.0' encoding='utf-8' ?>"+CRLF
cTesto += "<Configurazione>"+CRLF
cTesto += cSpazi+"<SET>"+CRLF
cSpazi := Space(4)
cTesto += cSpazi+"<NOME>"+SELF:Nome_SV+"</NOME>"+CRLF
cTesto += cSpazi+"<VOLUME>"+NTrim(SELF:nVolume)+"</VOLUME>"+CRLF
cTesto += cSpazi+"<RATE>"+NTrim(SELF:nRate)+"</RATE>"+CRLF
cTesto += cSpazi+"<ATTIVO>"+SELF:Attivo+"</ATTIVO>"+CRLF
cSpazi := Space(2)
cTesto += cSpazi+"</SET>"+CRLF
cTesto += "</Configurazione>"+CRLF

oStream := System.IO.StreamWriter{WorkDir()+"parla.xml"}
oStream:Write(cTesto)
oStream:Close()
ENDIF

RETURN

METHOD ChiudiParlato() AS VOID
//5) Per chiudere, quando esci dal programma:
IF IsInstanceOf(SELF:oVoce,"SpeechSynthesizer")
SELF:oVoce:Dispose()
ENDIF
RETURN

METHOD Voce(cTesto AS STRING,lFlag := FALSE AS LOGIC) AS VOID

IF IsInstanceOf(SELF:oVoce,"SpeechSynthesizer")
IF lFlag
SELF:oVoce:Speak(cTesto) //il programma si blocca fino alla fine della lettura del testo
ELSE
SELF:oVoce:SpeakAsync(cTesto) //Il programma continua l'esecuzione mentre parla
ENDIF
ENDIF

RETURN
METHOD Stop() AS VOID

IF IsInstanceOf(SELF:oVoce,"SpeechSynthesizer")
SELF:oVoce:Speak("") //il programma si blocca fino alla fine della lettura del testo
ENDIF

RETURN

METHOD Avviso(cTesto AS STRING) AS VOID //Oppure la tua Mostra
SELF:Voce(cTesto) //Viele letto il testo
System.Windows.Forms.MessageBox.Show(cTesto,"Avviso",System.Windows.Forms.MessageBoxButtons.OK,System.Windows.Forms.MessageBoxIcon.Information)
RETURN

END CLASS

#USING System.IO
#USING System.Data
#USING System.Windows.Forms

CLASS XML_File
PROTECT cFileXML AS STRING
PROTECT oDataTable AS DataTable //La tabella corrente (il nodo e le variabili)

PROTECT oDataSet AS DataSet //Contiene la struttura delfile XML
//Tante tabelle quanti sono i nodi, tante colonne
// quanto sono le variabili del nodo e tante
//righe quanti sono i nodi ripetuti.

PROTECT nNodi AS INT //Contiene il numero di tabelle lette dall'XML
//Ogni nodo è una tabella

PROTECT cSezione AS STRING // La tabella/il nodo corrente
PROTECT cVariabile AS STRING
PROTECT cValore AS STRING

PROTECT aSezioni AS ARRAY //Contiene il nome delle tabelle e la posizione
//nel DataSet

PROTECT aColonne AS ARRAY //Contiene le colonne della tabella

CONSTRUCTOR(cFile := "" AS STRING)

IF ! Empty(cFile)
IF File.Exists(cFile)
SELF:cFileXML := cFile
SELF:oDataSet := DataSet{}
SELF:oDataSet:ReadXml(SELF:cFileXML)

SELF:LeggiSezioni()
SELF:GetSection(SELF:aSezioni[1,1])
ELSE
MessageBox.Show("Attenzione, il file "+cFile+" non esiste." ,"Avviso",MessageBoxButtons.OK,MessageBoxIcon.Information)
ENDIF
ENDIF
RETURN

METHOD CreateFile(cFile AS STRING) AS VOID

SELF:oDataSet := DataSet{}
SELF:oDataSet:ReadXml(cFile)

SELF:LeggiSezioni()
SELF:GetSection(SELF:aSezioni[1,1])

RETURN

METHOD CreateSection(cNomeSezione AS STRING,cNomeVariabile := "" AS STRING,cValore := "" AS STRING) AS VOID
LOCAL oTable AS DataTable
LOCAL oColonna AS System.Data.DataColumn
LOCAL oDataRow AS DataRow

IF ! Empty(cNomeSezione) .and. ! Empty(cNomeVariabile)
oTable := DataTable{}
oTable:TableName := Upper(cNomeSezione)
oColonna := DataColumn{}
oColonna:DataType := System.Type.GetType("System.String")
oColonna:ColumnName := Upper(cNomeVariabile)
oTable:Columns:Add(oColonna)
oDataRow := oTable:NewRow()
oDataRow[cNomeVariabile] := cValore
oTable:Rows:Add(oDataRow)
SELF:oDataSet:Tables:Add(oTable)
SELF:LeggiSezioni()
ENDIF
RETURN
METHOD DeleteSection(uNomeNodo AS USUAL) AS LOGIC
LOCAL lOK := FALSE AS LOGIC
LOCAL nPos AS INT
LOCAL cNomeTabella AS STRING

IF ValType(uNomeNodo) == "C"
nPos := (INT) AScan(SELF:aSezioni,{|x| Upper(x[1]) == Upper(uNomeNodo)})
ELSEIF ValType(uNomeNodo) == "N"
nPos := (INT) AScan(SELF:aSezioni,{|x| x[2] == uNomeNodo})
ENDIF
IF nPos > 0
cNomeTabella := SELF:aSezioni[nPos,1]
SELF:oDataSet:Tables:Remove(cNomeTabella)
SELF:LeggiSezioni()
lOK := TRUE
ENDIF

RETURN lOK

METHOD CreateElement(cElemento AS STRING,cValore AS STRING,nPos := 0 AS INT) AS VOID
LOCAL nCol AS INT

SELF:oDataTable:Columns:Add(cElemento)
nCol := SELF:oDataTable:Columns:Count -1
SELF:oDataTable:Rows[nPos]:Item[nCol] := cValore
SELF:LeggiColonne(SELF:oDataTable)
RETURN
METHOD DeleteColumn(cSezione AS STRING, uElemento AS STRING) AS VOID
LOCAL nPos AS INT

SELF:GetSection(cSezione)
nPos := (INT) AScan(SELF:aColonne,{|x| Upper(x[1]) == Upper(uElemento)})
IF nPos > 0
SELF:oDataTable:Columns:RemoveAt(nPos-1)
SELF:LeggiColonne(SELF:oDataTable)
SELF:SaveXML(SELF:cFileXML)
ENDIF

RETURN

METHOD DeleteElement(uElemento AS USUAL) AS VOID
LOCAL nPos AS INT

IF ValType(uElemento) == "C"
nPos := (INT) AScan(SELF:aColonne,{|x| Upper(x[1]) == Upper(uElemento)})
ELSEIF ValType(uElemento) == "N"
nPos := (INT) AScan(SELF:aColonne,{|x| x[2] == uElemento})
ENDIF
IF nPos > 0
SELF:oDataTable:Columns:RemoveAt(nPos-1)
SELF:LeggiColonne(SELF:oDataTable)
ENDIF
RETURN

METHOD DeleteValue(cNomeSezione AS STRING,cColonna AS STRING, cValore AS STRING) AS VOID
LOCAL oDataView AS DataView
LOCAL n AS INT

SELF:GetSection(cNomeSezione)
oDataView := DataView{SELF:oDataTable}

oDataView:Sort := cColonna
n := oDataView:Find(cValore)
IF n <> -1
oDataView:Delete(n)
ENDIF
SELF:SaveXML(SELF:cFileXML)
RETURN

METHOD ExistSection(cNomeSezione AS STRING) AS LOGIC
RETURN ((INT) AScan(SELF:aSezioni,{|x| Upper(x[1]) == Upper(cNomeSezione)})) > 0

METHOD GetNodi() AS INT
RETURN SELF:nNodi
METHOD GetEntry(cNomeSezione AS STRING,cNomeVariabile AS STRING) AS STRING
LOCAL cValore AS STRING
LOCAL nPos AS INT
LOCAL oTable AS DataTable

TRY
cValore := ""
IF ! Empty(cNomeSezione) .and. ! Empty(cNomeVariabile)
IF (SELF:oDataTable:TableName == cNomeSezione)
cValore := Convert.ToString(SELF:oDataTable:Rows[0]:Item[cNomeVariabile])
ELSE
nPos := (INT) AScan(SELF:aSezioni,{|x| Upper(x[1]) == Upper(cNomeSezione)})
IF nPos > 0
oTable := SELF:oDataSet:Tables[nPos-1]
IF SELF:oDataSet:Tables[nPos-1]:Columns:Contains(cNomeVariabile)
cValore := Convert.ToString(oTable:Rows[0]:Item[cNomeVariabile])
ELSE
cValore := ""
ENDIF
ENDIF
ENDIF
ENDIF
CATCH
cValore := ""
END TRY

RETURN cValore

METHOD GetSection(uNomeNodo AS USUAL) AS DataTable
LOCAL nPos AS INT

SELF:oDataTable := DataTable{}
IF ValType(uNomeNodo) == "C"
nPos := (INT) AScan(SELF:aSezioni,{|x| Upper(x[1]) == Upper(uNomeNodo)})
ELSEIF ValType(uNomeNodo) == "N"
nPos := (INT) AScan(SELF:aSezioni,{|x| x[2] == uNomeNodo})
ENDIF
IF nPos > 0
SELF:oDataTable := SELF:oDataSet:Tables[nPos-1]
SELF:LeggiColonne(SELF:oDataTable)
ENDIF
RETURN SELF:oDataTable

METHOD GetArraySection(uNom
User avatar
Chris
Posts: 4898
Joined: Thu Oct 08, 2015 7:48 am
Location: Greece

Eseguire un file audio

Post by Chris »

Claudio,

There's also the SoundPlayer class which can play sounds, but it has limited functionality and can only play .wav files:

Code: Select all

LOCAL oPlayer AS System.Media.SoundPlayer
oPlayer := System.Media.SoundPlayer{"C:wavRing10.wav"}
oPlayer:Play()
Chris Pyrgas

XSharp Development Team
chris(at)xsharp.eu
FFF
Posts: 1580
Joined: Fri Sep 25, 2015 4:52 pm
Location: Germany

Eseguire un file audio

Post by FFF »

Claudio,
Ho fatto una prova veloce dell'applicazione Vo StdMDI in XIDE, usando il metodo Timer nella shell, nessun problema. La variante più semplice potrebbe essere:
METODO Timer() AS USUAL
IF yourDBCheck_Alert()
Tone(440,5)
Tone(660,5)
Tone(880,5)
Tone(1000,5)
ENDIF
RETURN TRUE
Regards
Karl
(on Win8.1/64, Xide32 2.20, X#2.20.0.3)
FFF
Posts: 1580
Joined: Fri Sep 25, 2015 4:52 pm
Location: Germany

Eseguire un file audio

Post by FFF »

Oppure, per essere un po' più fantasiosi, usate questo mio vecchio metodo di test come punto di partenza per farlo parlare:

USING System.Speech.Synthesis
USING System.Speech.AudioFormat
USING System.IO
FUNCTION EncodeNewNumbers(d AS STRING, val AS STRING ) AS LOGIC
LOCAL oSAFI AS SpeechAudioFormatInfo
oSAFI:=SpeechAudioFormatInfo{32000, AudioBitsPerSample.Sixteen, AudioChannel.Mono}

LOCAL Synth AS SpeechSynthesizer
Synth := SpeechSynthesizer{}

LOCAL cEinleitung AS STRING

cEinleitung:="Am" + d + " Dezember wurden folgende Nummern gezogen:"
Synth:Speak(cEinleitung + val)

/*
FOREACH v AS System.Speech.Synthesis.InstalledVoice IN Synth:GetInstalledVoices()
? v:VoiceInfo:Name
NEXT
*/

// Var 1 -> WAV File schreiben
//Synth:SetOutputToWaveFile( cPath, oSAFI)

RETURN TRUE
Regards
Karl
(on Win8.1/64, Xide32 2.20, X#2.20.0.3)
Post Reply