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
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
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 !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
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
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 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
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
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)
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)