Creare il blocco d'intestazione di un file WAV avendo dati audio grezzi
Avendo un flusso di dati audio grezzi e volendo crere con tali dati audio un file WAV, vedremo come poter impostare il blocco d'intestazione di tale file audio.
Il blocco di intestazione (header ) di un file WAV è posto all'inizio del file, solitamente formato da 44 byte, e contiene le informazioni generali sui dati audio e sul file medesimo. [Nota 1]
Per poter creare un blocco d'inteztazione di un file wav, è necessario tenere conto dei suoi elementi fondamentali:
- quantità dei dati audio grezzi (in byte);
- frequenza di campionamento (in hertz);
- risoluzione di campionamento (in bit);
- numero dei canali di uscita.
Da questi elementi principali è possibile individuare e quindi porre nel blocco di intestazione del file wav anche gli altri valori che lo compongono.
Mostriamo alcune modalità.
Negli esempi, che seguono, supporremo che i dati audio grezzi siano stati acquisiti in precedenza da un file avente le seguenti caratteristiche: 44100 hertz, 16 bit, 2 canali.
Si creerà un completo nuovo file WAV unendo il corretto blocco d'intestazione (header) a tali dati grezzi.
1a modalità
Questa modalità prevede che i byte, costituenti il blocco d'intestazione del file WAV da creare, siano già impostati all'interno di un array di tipo "Byte[]", fatta eccezione per i valori di tipo Integer previsti al 5° e al 40° byte.
Tali valori saranno comunque assegnati successivamente, quando si conoscerà la quantità di byte appartenenti ai dati grezzi audio.
Dim datigrezzi As String Dim st As Stream ' Si impostano i dati generali del blocco d'intestazione del futuro file WAV. ' = Blocco d'intestazione del file wav futuro: 2 canali, 16 bit, hz 44100 = Dim bh As Byte[] = [&52, &49, &46, &46, &00, &00, &00, &00, &57, &41, &56, &45, &66, &6D, &74, &20, &10, &00, &00, &00, &01, &00, &02, &00, &44, &AC, &00, &00, &10, &B1, &02, &00, &04, &00, &10, &00, &64, &61, &74, &61, &00, &00, &00, &00] datigrezzi = variabile_contenente_i_dati_audio_grezzi ' Imposta i dati di tipo "Integer" previsti al 5° e al 40° byte dell'intestazione del file WAV: st = Memory bh.Data For Write Seek #st, 4 Write #st, Len(datigrezzi) + 36 As Integer Seek #st, 40 Write #st, Len(datigrezzi) As Integer st.Close
2a modalità
Il procedimento del codice mostra l'inserimento passo-passo di ciascun elemento previsto dal blocco header del file wav.
Gli elementi non fondamentali verranno per lo più ricavati dai valori degli elementi fondamenti prima sopra elencati.
Private Procedure CreaHeaderWav(dati_grezzi As String) Dim fl As File Dim ini As String Dim bh, bb As New Byte[] Dim canali, risoluzione, blal as Byte Dim i, i2, frequenza, brps As Integer ' Vengono definiti gli elementi fondamentali del blocco d'intestazione del file wav: canali = 2 frequenza = 44100 risoluzione = 16 fl = Open "/percorso/di/destinazione/del/nuovo/file.wav" For Create ini = "RIFF" bb = Byte[].FromString(ini) i = Len(dati_grezzi) i2 = i + 36 ' Imposta il valore dimensionale di 4 byte a partire dal 5° byte del futuro file: bb.Push(i2 And &FF) bb.Push(Shr(i2 And &FF00&, 8)) bb.Push(Shr(i2 And &FF0000&, 16)) bb.Push(Shr(i2 And &FF000000&, 24)) ' Vengono aggiunti: il tipo di formato di file e l'identificativo del formato del sotto-blocco dei dati audio ("fmt"): bb.Insert(bh.FromString("WAVEfmt ")) ' Viene aggiunto il valore della lunghezza del sotto-blocco "fmt": bh = [&10, &00, &00, &00] bb.Insert(bh) ' Viene aggiunto il valore del formato audio (1 = PCM): [Nota 2] bb.Insert(bh.FromString(Chr(&01) & Chr(&00))) ' Viene aggiunto il numero dei canali di uscita: bb.Insert(bh.FromString(Chr(canali) & Chr(&00))) ' Viene aggiunto il valore della frequenza di campionamento: bb.Push(frequenza And &FF) bb.Push(Shr(frequenza And &FF00&, 8)) bb.Push(Shr(frequenza And &FF0000&, 16)) bb.Push(Shr(frequenza And &FF000000&, 24)) ' Viene aggiunto il valore del "Byte rate per secondo": brps = frequenza * canali * (risoluzione / 8) bb.Push(brps And &FF) bb.Push(Shr(brps And &FF00&, 8)) bb.Push(Shr(brps And &FF0000&, 16)) bb.Push(Shr(brps And &FF000000&, 24)) ' Viene aggiunto il valore del "Block Align": blal = canali * risoluzione / 8 bb.Insert(bh.FromString(Chr(blal) & Chr(&00))) ' Viene aggiunto il valore della risoluzione di campionamento: bb.Insert(bh.FromString(Chr(risoluzione) & Chr(&00))) ' Viene aggiunto l'identificativo del Blocco dei dati audio grezzi: bb.Insert(bh.FromString("data")) ' Imposta il valore dimensionale di 4 byte a partire dal 41° byte del futuro file e relativo alla dimensione dei dati audio grezzi: bb.Push(i And &FF) bb.Push(Shr(i And &FF00&, 8)) bb.Push(Shr(i And &FF0000&, 16)) bb.Push(Shr(i And &FF000000&, 24)) bb.Insert(Byte[].FromString(dati_grezzi)) ' Crea il nuovo file wav: bb.Write(fl, 0, bb.Count) fl.Close End
3a modalità
In questo caso imposteremo i dati del blocco d'intestazione del file WAV in un vettore di tipo "Byte[]" mediante la risorsa Memory Stream operando sulla Proprietà ".Data" del predetto vettore.
Nell'esempio che segue poniamo il caso che i dati audio grezzi abbiano le seguenti caratteristiche:
- frequenza di campionamento = 44100 hertz;
- numero canali = 2;
- risoluzione = 16 bit.
Private Const FREQUENZA As Integer = 44100 Private Const RISOLUZIONE As Short = 16 Private Const CANALI As Short = 2 Private Function BloccoIntestazione(quantità_dati_grezzi As Integer, bb As Byte[]) Dim st As Stream bb = New Byte[44 + quantità_dati_grezzi] st = Memory bb.Data For Write ' ID del blocco del tipo "RIFF": Write #st, "RIFF" ' quantità dei successivi byte del blocco d'intestazione + quantità dei dati audio grezzi: Write #st, 36 + quantità_dati_grezzi As Integer ' sottotipo file "wav" e sotto-blocco "fmt " del file: Write #st, "WAVEfmt " ' lunghezza del blocco "fmt": Write #st, 16 As Integer ' formato MS PCM: Write #st, 1 As Short ' canali audio di ucita (mono = 1, stereo = 2): Write #st, CANALI As Short ' frequenza di campionamento per secondo: Write #st, FREQUENZA As Integer ' byte-rate per secondo = frequenza * canali * (risoluzione / 8): Write #st, FREQUENZA * CANALI * (RISOLUZIONE / 8) As Integer ' block align (byte per campione) = canali * risoluzione / 8: Write #st, CANALI * RISOLUZIONE / 8 As Short ' bit per campione (risoluzione del campionamento): Write #st, RISOLUZIONE As Short ' ID del sotto-blocco "data": Write #st, "data" ' quantità dei dati audio grezzi: Write #st, quantità_dati_grezzi As Integer st.Close End
4a modalità
In quest'altro caso imposteremo i dati del blocco d'intestazione del file WAV in un flusso di dati di tipo File mediante le risorse "OPER" e "WRITE".
Anche in questo caso si assumerà che i dati audio grezzi abbiano le seguenti caratteristiche:
- frequenza di campionamento = 44100 hertz;
- numero canali = 2;
- risoluzione = 16 bit.
L'esempio prevede che si disponga di dati audio grezzi, contenuti in una variabile di tipo Stringa. Al termine con tali dati audio grezzi verrà creato un nuovo file WAV.
Private Const FREQUENZA As Integer = 44100 Private Const RISOLUZIONE As Short = 16 Private Const CANALI As Short = 2 Private Sub Main() Dim datigrezzi As String Dim bb1, bb2 As Byte[] datigrezzi = variabile_stringa_contenente_i_dati-byte_audio_grezzi ' Carica nel vettore i dati-byte audio grezzi: bb2 = Byte[].FromString(datigrezzi) ' Carica nel vettore i dati-byte del blocco d'intestazione del futuro file wav: bb1 = Byte[].FromString(File.Load(BloccoIntestazione(datigrezzi.Len))) File.Save("/tmp/nuovofile.wav", bb1.Insert(bb2).toString(0, bb1.Count)) End Private Function BloccoIntestazione(datigrezzi As Integer) As String Dim fl As File Dim blocco As String blocco = Temp fl = Open blocco For Create ' ID del blocco del tipo "RIFF": Write #fl, "RIFF" ' quantità dei successivi byte del blocco d'intestazione + quantità dei dati audio grezzi: Write #fl, (36 + datigrezzi) As Integer ' sottotipo file "wav" e sotto-blocco "fmt " del file: Write #fl, "WAVEfmt " ' lunghezza del blocco "fmt": Write #fl, 16 As Integer ' formato MS PCM: Write #fl, 1 As Short ' canali audio di ucita (mono = 1, stereo = 2): Write #fl, CANALI As Short ' frequenza di campionamento per secondo: Write #fl, FREQUENZA As Integer ' byte-rate per secondo: Write #fl, FREQUENZA * CANALI * (RISOLUZIONE / 8) As Integer ' block align (byte per campione): Write #fl, CANALI * RISOLUZIONE / 8 As Short ' bit per campione (risoluzione del campionamento): Write #fl, RISOLUZIONE As Short ' ID del sotto-blocco "data": Write #fl, "data" ' quantità dei dati audio grezzi: Write #fl, datigrezzi As Integer fl.Close Return blocco End
Note
[1] Vedere anche la seguente pagina: Estrarre informazioni da un file .wav
[2] Di seguito l'elenco dei formati disponibili:
&h0000: "Microsoft Unknown Wave Format"; &h0001: "Microsoft PCM"; &h0002: "Microsoft ADPCM"; &h0003: "IEEE Float"; &h0004: "Compaq Computer VSELP"; &h0005: "IBM CVSD"; &h0006: "Microsoft A-Law"; &h0007: "Microsoft mu-Law"; &h0008: "Microsoft DTS"; &h0009: "Microsoft DRM Encrypted Audio"; &h000A: "Windows Media Audio 9 Voice"; &h000B: "Windows Media RT Voice"; &h0010: "OKI ADPCM"; &h0011: "Intel DVI/IMA ADPCM"; &h0012: "Videologic MediaSpace ADPCM"; &h0013: "Sierra ADPCM"; &h0014: "Antex G.723 ADPCM"; &h0015: "DSP Solutions DigiSTD"; &h0016: "DSP Solutions DigiFIX"; &h0017: "Dialogic OKI ADPCM"; &h0018: "MediaVision ADPCM"; &h0019: "Hewlett-Packard CU"; &h0020: "Yamaha ADPCM"; &h0021: "Speech Compression Sonarc"; &h0022: "DSP Group TrueSpeech"; &h0023: "Echo Speech EchoSC1"; &h0024: "Audiofile AF36"; &h0025: "Audio Processing Technology APTX"; &h0026: "AudioFile AF10"; &h0027: "Prosody 1612"; &h0028: "LRC"; &h0030: "Dolby AC2"; &h0031: "Microsoft GSM 6.10"; &h0032: "MSNAudio"; &h0033: "Antex ADPCME"; &h0034: "Control Resources VQLPC"; &h0035: "DigiREAL"; &h0036: "DigiADPCM"; &h0037: "Control Resources CR10"; &h0038: "Natural MicroSystems VBXADPCM"; &h0039: "Crystal IMA ADPCM"; &h003A: "EchoSC3"; &h003B: "Rockwell ADPCM"; &h003C: "Rockwell Digit LK"; &h003D: "Xebec"; &h0040: "Antex Electronics G.721 ADPCM"; &h0041: "G.728 CELP"; &h0042: "MS G.723"; &h0043: "MS G.723.1"; &h0044: "MS G.729"; &h0045: "SP G.726"; &h0050: "MPEG Layer-2 or Layer-1"; &h0052: "RT24"; &h0053: "PAC"; &h0055: "MPEG Layer-3"; &h0059: "Lucent G.723"; &h0060: "Cirrus"; &h0061: "ESPCM"; &h0062: "Voxware"; &h0063: "Canopus Atrac"; &h0064: "G.726 ADPCM"; &h0065: "G.722 ADPCM"; &h0066: "DSAT"; &h0067: "DSAT Display"; &h0069: "Voxware Byte Aligned"; &h0070: "Voxware AC8"; &h0071: "Voxware AC10"; &h0072: "Voxware AC16"; &h0073: "Voxware AC20"; &h0074: "Voxware MetaVoice"; &h0075: "Voxware MetaSound"; &h0076: "Voxware RT29HW"; &h0077: "Voxware VR12"; &h0078: "Voxware VR18"; &h0079: "Voxware TQ40"; &h0080: "Softsound"; &h0081: "Voxware TQ60"; &h0082: "MSRT24"; &h0083: "G.729A"; &h0084: "MVI MV12"; &h0085: "DF G.726"; &h0086: "DF GSM610"; &h0088: "ISIAudio"; &h0089: "Onlive"; &h0091: "SBC24"; &h0092: "Dolby AC3 SPDIF"; &h0093: "MediaSonic G.723"; &h0094: "Aculab PLC Prosody 8kbps"; &h0097: "ZyXEL ADPCM"; &h0098: "Philips LPCBB"; &h0099: "Packed"; &h00FF: "AAC"; &h0100: "Rhetorex ADPCM"; &h0101: "IBM mu-law"; &h0102: "IBM A-law"; &h0103: "IBM AVC ADPCM"; &h0111: "Vivo G.723"; &h0112: "Vivo Siren"; &h0123: "Digital G.723"; &h0125: "Sanyo LD ADPCM"; &h0130: "Sipro Lab Telecom ACELP NET / RealAudio 4.0/5.0)"; &h0131: "Sipro Lab Telecom ACELP 4800"; &h0132: "Sipro Lab Telecom ACELP 8V3"; &h0133: "Sipro Lab Telecom G.729"; &h0134: "Sipro Lab Telecom G.729A"; &h0135: "Sipro Lab Telecom Kelvin"; &h0140: "Windows Media Video V8"; &h0150: "Qualcomm PureVoice"; &h0151: "Qualcomm HalfRate"; &h0155: "Ring Zero Systems TUB GSM"; &h0160: "Microsoft Audio 1"; &h0161: "Windows Media 7/8/9"; &h0162: "Windows Media 9 Professional"; &h0163: "Windows Media 9 Lossess"; &h0164: "Windows Media Professional over S/PDIF"; &h0180: "MPEG-2 AAC"; &h0190: "DTS"; &h0200: "Creative Labs ADPCM"; &h0202: "Creative Labs FastSpeech8"; &h0203: "Creative Labs FastSpeech10"; &h0210: "UHER Informatic GmbH ADPCM"; &h0215: "Ulead DV Audio NTSC"; &h0216: "Ulead DV Audio PAL"; &h0220: "Quarterdeck"; &h0230: "I-link Worldwide VC"; &h0240: "Aureal RAW Sport"; &h0250: "Interactive Products HSX"; &h0251: "Interactive Products RPELP"; &h0260: "Consistent Software CS2"; &h0270: "Sony SCX / RealAudio 8.0"; &h0271: "Sony SCY"; &h0272: "Sony ATRAC3"; &h0273: "Sony SPC"; &h0300: "Fujitsu FM Towns Snd"; &h0400: "BTV Digital"; &h0401: "Intel Music Coder"; &h0450: "QDesign Music"; &h0680: "VME VMPCM"; &h0681: "AT&T Labs TPC"; &h08AE: "ClearJump LiteWave"; &h1000: "Olivetti GSM"; &h1001: "Olivetti ADPCM"; &h1002: "Olivetti CELP"; &h1003: "Olivetti SBC"; &h1004: "Olivetti OPR"; &h1100: "L&H Codec"; &h1101: "L&H CELP"; &h1102: "L&H SBC 0x1102"; &h1103: "L&H SBC 0x1103"; &h1104: "L&H SBC 0x1104"; &h1400: "Norris"; &h1401: "AT&T ISIAudio"; &h1500: "Soundspace Music Compression"; &h181C: "VoxWare RT24 Speech"; &h1971: "Sonic Foundry Perfect Clarity Audio (PCA)"; &h1FC4: "NCT Soft ALF2CD"; &h2000: "Dolby AC3"; &h2001: "Dolby DTS"; &h2002: "RealAudio 1.0 (14.4K)"; &h2003: "RealAudio 2.0 (28.8K)"; &h2004: "RealAudio G2 (Cook)"; &h2005: "RealAudio 3.0 (DolbyNet AC3)"; &h2006: "RealAudio 10.0 (LC-AAC)"; &h2007: "RealAudio 10.0 (HE-AAC)"; &h2048: "Sonic"; &h4143: "Divio AAC"; &h4201: "Nokia AMR"; &h566F: "Vorbis"; &h5756: "WavPack"; &h674F: "Ogg Vorbis 1"; &h6750: "Ogg Vorbis 2"; &h6751: "Ogg Vorbis 3"; &h676F: "Ogg Vorbis 1+"; &h6770: "Ogg Vorbis 2+"; &h6771: "Ogg Vorbis 3+"; &h7A21: "Adaptive Multirate"; &h7A22: "Adaptive Multirate w/ silence detection"; &h706D: "AAC"; &h77A1: "TTA"; &hA106: "MPEG-4 AAC"; &hA109: "Speex"; &hF1AC: "FLAC"