Visualizzazione dei risultati da 1 a 2 su 2
  1. #1

    attaccare due file wave

    Devo fare un applicazione (activeX visual basic, pilotato poi da una pagina asp) che deve riprodurre, mixare, attaccare dei file wave, poi convertirli in mp3.
    Per la conversione da wave a mp3 non ci son problemi, nemmeno per il mixaggio di file wave, ho trovato già activeX che fanno al caso mio.
    Per la riproduzione uso le directX 8, più precisamente le directSound, e anche qua non ci sono problemi.
    I problemi li ho nell'attaccare due file wave. Si presuppone che i due file abbiano le stesse caratteristiche, bit rate, numero canali, frequenza, ecc...
    Voglio creare una procedura che dati in ingresso i due file wave, mi crei un terzo file con i due file attacccati, uno dietro l'altro, senza pause in mezzo e nessun effetto sonoro.
    Ho trovato due vie, una usando i buffer di directSound, e un'altra a più basso livello che crea il file wave byte per byte. In entrambi i casi uso una procedura che mi estrae l'header del file wave (una struttura di alcuni byte contente le informazioni sul file) e la parte puramente di dati, così da avere una variabile con l'header del file (che è più o meno lo stesso per i due file wave, se hanno le stesse caratteristiche) e un array di byte che contiene la parte dati del file wave (in pratica le note da suonare). A questo punto non mi resta che attaccare le due parti dati dei due file wave assieme, e poi riassemblare il tutto con l'header (contente le informazioni sul bit rate, numero canali, frequenza,...) opportunamente modificato (occorre cambiare il campo che indica la lunghezza della parte dati). Per fare ciò ho provato con due diverse strade:
    - directSound (attaccaFile). Creo un buffer audio vuoto con le caratteristiche del file wave (che ricavo dall'header) e ci scrivo dentro la parte dati completa dei due blocchi di dati wave. Poi con un metodo del buffer salvo il tutto su un file su disco.
    - file binario (attaccaFile2). Stando a basso livello, tratto il tutto come file binario. Mi riscrivo da zero l'header del file wave, inserendovi le caratteristiche ricavate in precedenza, poi inserisco la parte di dati del primo file, poi inserisco la parte di dati del secondo file. Ho così creato il file wave. A differenza del metodo di prima, che mi scrive l'header in automatico, qua mi creo il file wave direttamente da zero.
    In via teorica mi sembra tutto corretto, in pratica invece mi funziona solo se uso dei file wave 8bit mono, cioè coi parametri del waveFormat
    - nChannels = 1 (mono)
    - nAvgBytesPerSec = 8 (8 bit)
    Con qualsiasi altro tipo di campionamento del file wave, 16 bit, stereo, ecc... non mi funziona come dovrebbe. Mi riproduce correttamente solo la prima metà del file (cioè il primo file) e l'altro si sentono dei fruscii, stridolii, e del casino.


    CODICE VB:

    Private Type FileHeader
    lRiff As Long
    lFileSize As Long
    lWave As Long
    lFormat As Long
    lFormatLength As Long
    End Type

    Private Type waveFormat
    wFormatTag As Integer
    nChannels As Integer
    nSamplesPerSec As Long
    nAvgBytesPerSec As Long
    nBlockAlign As Integer
    wBitsPerSample As Integer
    End Type

    Private Type ChunkHeader
    lType As Long
    lLen As Long
    End Type

    Private Type WAVETYPE
    strHead As String * 12
    strFormatID As String * 4
    lngChunkSize As Long
    intFormat As Integer
    intChannels As Integer
    lngSamplesPerSec As Long
    lngAvgBytesPerSec As Long
    intBlockAlign As Integer
    intBitsPerSample As Integer
    End Type

    Global gudtHeader As WAVETYPE 'header del file wave
    Global glngChunkSize1 As Long 'dimensione primo blocco dati wav
    Global gbytData1() As Byte 'primo blocco dati wav
    Global glngChunkSize2 As Long 'dimensione secondo blocco dati wav
    Global gbytData2() As Byte 'secondo blocco dati wav

    'DirectX Variable
    Dim mobjDX As DirectX8
    Dim mobjDS As DirectSound8
    Global objBuffer As DirectSoundSecondaryBuffer8


    Public Sub Initialize(frmInit As Form)
    'Initialize DirectSound
    Set mobjDX = New DirectX8
    Set mobjDS = mobjDX.DirectSoundCreate("")

    'Set the DirectSound object's cooperative level (Priority gives us sole control)
    mobjDS.SetCooperativeLevel frmInit.hWnd, DSSCL_PRIORITY
    End Sub


    Sub ExtractWaveData1(strFileName As String, lngOffset As Long)
    Dim intWAVFile As Integer
    Dim i As Long
    Dim strTemp As String * 4
    Dim blnFound As Boolean

    'Open the wave
    intWAVFile = FreeFile()
    Open strFileName For Binary Access Read Lock Write As intWAVFile
    'Get the header info
    Get intWAVFile, lngOffset, gudtHeader
    'Find the "data" portion of the file
    For i = lngOffset To LOF(intWAVFile)
    Get intWAVFile, i, strTemp
    If strTemp = "data" Then
    blnFound = True
    Exit For
    End If
    Next i
    'Ensure this is a wave file
    If blnFound = False Then
    MsgBox "Invalid wave data.", vbCritical, "Invalid Wave"
    Close intWAVFile
    Exit Sub
    End If
    'Get the data information
    Get intWAVFile, , glngChunkSize1
    ReDim gbytData1(glngChunkSize1)
    Get intWAVFile, , gbytData1
    Close intWAVFile
    End Sub


    Sub ExtractWaveData2(strFileName As String, lngOffset As Long)
    Dim intWAVFile As Integer
    Dim i As Long
    Dim strTemp As String * 4
    Dim blnFound As Boolean

    'Open the wave
    intWAVFile = FreeFile()
    Open strFileName For Binary Access Read Lock Write As intWAVFile
    'Get the header info
    Get intWAVFile, lngOffset, gudtHeader
    'Find the "data" portion of the file
    For i = lngOffset To LOF(intWAVFile)
    Get intWAVFile, i, strTemp
    If strTemp = "data" Then
    blnFound = True
    Exit For
    End If
    Next i
    'Ensure this is a wave file
    If blnFound = False Then
    MsgBox "Invalid wave data.", vbCritical, "Invalid Wave"
    Close intWAVFile
    Exit Sub
    End If
    'Get the data information
    Get intWAVFile, , glngChunkSize2
    ReDim gbytData2(glngChunkSize2)
    Get intWAVFile, , gbytData2
    Close intWAVFile
    End Sub


    Public Sub AttaccaFile(file1 As String, file2 As String, fileSomma As String)
    'gli vengono passati i nomi dei file da attaccare (file1 e file2) e il file creato su cui attaccarli (filesomma)

    Dim udtBufferDesc As DSBUFFERDESC
    Dim intBinaryFile As Integer
    Dim gbytDataTot() As Byte

    'Extract the wave info
    ExtractWaveData1 file1, 1
    ExtractWaveData2 file2, 1

    'ora ho in variabili globali la dimensione e i blocchi di dati wav, e in gutHeader l'header del file
    '(si presuppone che i due file da attaccare abbiano le stesse caratteristiche)

    'Set the Wave Format
    With udtBufferDesc.fxFormat
    .nFormatTag = gudtHeader.intFormat
    .nChannels = gudtHeader.intChannels 'funziona solo se questo è = 1
    .lSamplesPerSec = gudtHeader.lngSamplesPerSec
    .nBitsPerSample = gudtHeader.intBitsPerSample 'funziona solo se questo è = 8
    .nBlockAlign = gudtHeader.intBlockAlign
    .lAvgBytesPerSec = gudtHeader.lngAvgBytesPerSec
    End With
    udtBufferDesc.lBufferBytes = glngChunkSize1 + glngChunkSize2

    'apro un file binario per scriverci i due blocchi di dati wav
    intBinaryFile = FreeFile
    Open App.Path & "\BINARY.DAT" For Binary Access Write Lock Write As intBinaryFile

    'Store the data in the file
    Put intBinaryFile, 1, gbytData1
    Put intBinaryFile, , gbytData2

    'Close the file
    Close intBinaryFile

    ReDim gbytDataTot(glngChunkSize1 + glngChunkSize2)

    intBinaryFile = FreeFile
    Open App.Path & "\BINARY.DAT" For Binary Access Read Lock Write As intBinaryFile

    'metto in gbytDataTot i due blocchi di wav attaccati
    Get intBinaryFile, 1, gbytDataTot

    'Close the file
    Close intBinaryFile

    'ora in gbytDataTot ho la parte dati dei due file wave attaccati, non mi resta che attaccarci l'header con directSound

    'Create the buffer
    Set objBuffer = Nothing
    Set objBuffer = mobjDS.CreateSoundBuffer(udtBufferDesc)

    'Load the buffer with data
    objBuffer.WriteBuffer 0, glngChunkSize1 + glngChunkSize2, gbytDataTot(0), DSBLOCK_ENTIREBUFFER

    'play
    objBuffer.Play DSBPLAY_DEFAULT

    'salvo il risultato sul file fileSomma
    objBuffer.SaveToFile fileSomma
    End Sub


    Public Sub AttaccaFile2(file1 As String, file2 As String, fileSomma As String)
    'gli vengono passati i nomi dei file da attaccare (file1 e file2) e il file creato su cui attaccarli (filesomma)

    Dim fh As FileHeader
    Dim wf As waveFormat
    Dim ch As ChunkHeader

    Dim dsBuf As DSBUFFERDESC
    Dim intBinaryFile As Integer
    Dim gbytDataTot() As Byte
    Dim fsize As Long

    'Extract the wave info
    ExtractWaveData1 file1, 1
    ExtractWaveData2 file2, 1

    'ora ho in variabili globali la dimensione e i blocchi di dati wav, e in gutHeader l'header del file
    '(si presuppone che i due file da attaccare abbiano le stesse caratteristiche)

    'creo il file che conterrà i due wave attaccati
    intBinaryFile = FreeFile
    Open fileSomma For Binary Access Write As intBinaryFile

    With fh
    .lRiff = &H46464952 ' <RIFF> chunk tag
    .lFileSize = 0 ' Will get later
    .lWave = &H45564157 ' <WAVE> chunk tag
    .lFormat = &H20746D66 ' <fmt > chunk tag
    .lFormatLength = Len(wf)
    End With

    Put #1, , fh

    With wf
    .wFormatTag = WAVE_FORMAT_PCM
    .nChannels = gudtHeader.intChannels 'funziona solo se questo è = 1
    .nSamplesPerSec = gudtHeader.lngSamplesPerSec
    .wBitsPerSample = gudtHeader.intBitsPerSample 'funziona solo se questo è = 8
    .nBlockAlign = gudtHeader.intBlockAlign
    .nAvgBytesPerSec = gudtHeader.lngAvgBytesPerSec
    End With

    Put #1, , wf

    ch.lType = &H61746164 ' <data> chunk tag

    Put #1, , ch

    ' Write file size.
    fsize = Len(fh) + Len(wf) + Len(ch) + glngChunkSize1 + glngChunkSize2
    Put #1, 5, fsize

    ' Rewrite data chunk header with size.
    ch.lLen = glngChunkSize1 + glngChunkSize2
    Put #1, Len(fh) + Len(wf) + 1, ch

    'Store the data in the file
    Put intBinaryFile, Len(fh) + Len(wf) + Len(ch) + 1, gbytData1
    Put intBinaryFile, , gbytData2

    'Close the file
    Close intBinaryFile

    'Create the buffer to play file
    dsBuf.lFlags = DSBCAPS_CTRLFREQUENCY Or DSBCAPS_CTRLPAN Or DSBCAPS_CTRLVOLUME
    Set objBuffer = Nothing
    Set objBuffer = mobjDS.CreateSoundBufferFromFile(fileSomma, dsBuf)
    'play
    objBuffer.Play DSBPLAY_DEFAULT
    End Sub


    Public Sub Terminate()
    'Terminate all
    Set mobjDS = Nothing
    Set mobjDX = Nothing
    Set objBuffer = Nothing
    End Sub
    sero asp warrior

  2. #2
    Ho trovato la soluzione al mio problema.
    L'errore stava qua:

    'Store the data in the file
    Put intBinaryFile, Len(fh) + Len(wf) + Len(ch) + 1, gbytData1
    Put intBinaryFile, , gbytData2

    Bisogna specificare correttamente anche la posizione di scrittura del secondo array di byte:

    'Store the data in the file
    Put intBinaryFile, Len(fh) + Len(wf) + Len(ch) + 1, gbytData1
    Put intBinaryFile, Len(fh) + Len(wf) + Len(ch) + 1 + glngChunkSize1, gbytData2

    così funziona con tutti i tipi di wave.

    sero
    sero asp warrior

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.