Italian [B4A] Salvare e aprire audiostreamer [RISOLTO]

Aldo's

Active Member
Licensed User
Buongiorno a tutti.
Grazie alla libreria AudioRecord ho visto che è possibile registrare e riprodurre degli audio streamer.
Ora vorrei salvarli e aprirli con un titolo memorizzato in un SQLite.
Come posso salvare un audiostreamer?
Come lo apro?
Grazie a tutti
 

udg

Expert
Licensed User
Longtime User
Ciao. Quello che chiedi è esattamente ciò che ho fatto per JustNotes, la mia app personale per la registrazione di note testuali ed audio.
Il file audio prodotto dal componente è un WAV. La particolarità di AudioStreamer è che la registrazione avviene in blocchi (i buffer che vedi menzionati) generati automaticamente. Quindi, quando salvi, devi salvare tutti i blocchi.
Il formato WAV ha una sua struttura specifica e per tale motivo il salvataggio su file avviene in due tempi, prima i buffer e poi la lunghezza totale.

B4X:
'Salva il file WAV sul device, memoria interna
    Dim output As OutputStream
    output = StartWaveFile(MP.DBFolder&"/audio", mFileName, MP.mSampleRate, MP.mMono, MP.mBitRate)
    For Each buffer() As Byte In buffers
        output.WriteBytes(buffer, 0, buffer.Length)
    Next
    output.Close
    CloseWaveFile(MP.DBFolder&"/audio", mFileName)

'Predispone output di WAV file
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

'Finalizza e chiude WAV file
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)
    Log(raf.size)
    raf.Close
End Sub

Edit: dire che il file audio prodotto dal componente sia un WAV è errato. Per due motivi: Audiostreamer di suo non produce alcun file; il salvataggio in formato WAV è solo una delle possibilità di riversare i buffer su un file. Conoscendo la struttura di un diverso tipo di file si potrebbe salvare in un diverso formato. Al peggio si sarà costretti a lavorare il contenuto dei buffer per allinearsi a quanto previsto dal nuovo formato.
 
Last edited:

Aldo's

Active Member
Licensed User
Ciao. Quello che chiedi è esattamente ciò che ho fatto per JustNotes, la mia app personale per la registrazione di note testuali ed audio.
Il file audio prodotto dal componente è un WAV. La particolarità di AudioStreamer è che la registrazione avviene in blocchi (i buffer che vedi menzionati) generati automaticamente. Quindi, quando salvi, devi salvare tutti i blocchi.
Il formato WAV ha una sua struttura specifica e per tale motivo il salvataggio su file avviene in due tempi, prima i buffer e poi la lunghezza totale.

B4X:
'Salva il file WAV sul device, memoria interna
    Dim output As OutputStream
    output = StartWaveFile(MP.DBFolder&"/audio", mFileName, MP.mSampleRate, MP.mMono, MP.mBitRate)
    For Each buffer() As Byte In buffers
        output.WriteBytes(buffer, 0, buffer.Length)
    Next
    output.Close
    CloseWaveFile(MP.DBFolder&"/audio", mFileName)

'Predispone output di WAV file
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

'Finalizza e chiude WAV file
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)
    Log(raf.size)
    raf.Close
End Sub
Wow, grazie per la spiegazione e la condivisione.
Guardo il codice, provo ad adattarlo e poi ti dico.
 

Aldo's

Active Member
Licensed User
Bellissimo, chiarissimo e, soprattutto, funziona.
Ho salvato.
Per recuperare il file, conoscendo il titolo, come procedo?
E' necessario usare l'estensione wav o no?
Grazie
 

udg

Expert
Licensed User
Longtime User
Sì, certo.
Io uso codice di questo tipo quando fai click su una nota audio
B4X:
If mp.IsInitialized And File.Exists(DBFolder&"/audio", mfilename) Then
                Try
                    mp.Load(DBFolder&"/audio", mfilename)
                    mp.Play
                Catch
                    Log(LastException)
                End Try
            End If
Con mfilename del tipo: 0001.wav
Da notare che per il playback di audio registrati in precedenza utilizzo il MediaPlayer. Sembra che non si riesca ad "iniettare" nel buffer interno di AudioStreamer un audio esistente.. quindi MediaPlayer!
 

Aldo's

Active Member
Licensed User
Spero ultima domanda per rendere completo il tutto.
Il nome del file che tu nel primo codice hai chiamato mFileName è comprensivo di ".wav" o non è da specificare?
Grazie
 

udg

Expert
Licensed User
Longtime User
Sì. Io uso un nome "numerico" )in pratica un progressivo), seguito dall'estensione ".wav".
Non so se MediaPlayer sia in grado di riconoscere un wav anche senza estensione. Puoi provare. In caso affermativo potresti salvare e poi leggere il file audio senza alcuna estensione. Altrimenti ti toccherà specificarla.
 

Aldo's

Active Member
Licensed User
Ho già risolto aggiungendo l'estensione.
Grazie ancora per l'enorme aiuto.
 
  • Like
Reactions: udg
Top