Suddividere in due o più parti coerenti e funzionali un file audio mp3

Da Gambas-it.org - Wikipedia.

Il seguente codice è un'applicazione per dividere in due o più parti coerenti e funzionali un file audio di formato mp3.

Da notare che questa operazione causa la perdita degli eventuali tag ID3 del file; quindi si consiglia di rimuovere tutti i TAG originari e di fare una operazione di ri-codifica successivamente.

**********************************************************************************************************
Il presente codice è la traduzione in Gambas con variazioni ed integrazioni, del codice originale,
scritto in linguaggio C, del progetto di Kjetil Erga, chiamato "MP3 Splitting Tool".
**********************************************************************************************************


Private bitrate_matrix As Integer[][] = [[0, 0, 0, 0, 0], [32, 32, 32, 32, 8], [64, 48, 40, 48, 16],
        [96, 56, 48, 56, 24], [128, 64, 56, 64, 32], [160, 80, 64, 80, 40], [192, 96, 80, 96, 48],
        [224, 112, 96, 112, 56], [256, 128, 112, 128, 64], [288, 160, 128, 144, 80],
        [320, 192, 160, 160, 96], [352, 224, 192, 176, 112], [384, 256, 224, 192, 128],
        [416, 320, 256, 224, 144], [448, 384, 320, 256, 160], [0, 0, 0, 0, 0]]

Private sampling_matrix As Integer[][] = [[44100, 22050, 11025], [48000, 24000, 12000],
                                         [32000, 16000, 8000], [0, 0, 0]]
                                          

Public Sub Main()
 
 Dim i, num_frame, parti, limes As Integer
 Dim src, dst As File
 Dim filename, parte As String
 
 filename = "/percorso/del/file.mp3"
   
' Stabiliamo che il file mp3 sarà suddiviso - ad esempio - in tre sotto-file:
 parti = 3
 If parti = 0 Then Error.Raise("Numero di parti non valido !")
 
 src = Open filename For Read
 Write #File.out, "\e[5mAttendere..."
   
 num_frame = read_frames(src, Null, 0)
 If parti > num_frame Then Error.Raise("Sono state specificate più parti che frame disponibili !")
   
 Seek #src, 0
 
 For i = 1 To parti
   parte = filename & "." & Format(i, "00")
   dst = Open parte For Create
   If IsNull(dst) Then Error.Raise("Impossibile aprire il file audio in scrittura !")
   If i = parti Then
     limes = 0
   Else
     limes = num_frame / parti
   Endif
   Write #File.Out, "\r\e[0m" & Format(i, "00:") & "  " & parte & ":" & "  " & CStr(read_frames(src, dst, limes))
   Print
   Write #File.out, "\e[5mAttendere..."
   dst.Close
 Next
 
 Print #File.Out, "\r\e[0m               "
 src.Close
 
End


Private Function read_frames(sor As File, des As File, frame_limes As Integer) As Integer
 
 Dim n, lung_frame, num_frame As Integer
 Dim b As Byte
 Dim quad As New Byte[4]
 
 quad[0] = 0
 quad[1] = 0
 quad[2] = 0
 quad[3] = 0
   
 lung_frame = 0
 n = 0
 num_frame = 0
   
 While Not Eof(sor)
   Read #sor, b
   If Not IsNull(des) Then Write #des, b As Byte
   If lung_frame > 0 Then
     Dec lung_frame
     Inc n
     If frame_limes > 0 Then
       If (lung_frame = 0) And (num_frame = frame_limes) Then Return num_frame
     Endif
' Va avanti nel flusso per evitare la lettura di dati inutili:
     Continue
   Endif
   quad[0] = quad[1]
   quad[1] = quad[2]
   quad[2] = quad[3]
   quad[3] = b
   If ((quad[0] = &FF) And ((quad[1] And &F0) = &F0)) Then
     Inc num_frame
     lung_frame = decode_header(quad) - 4
     quad[0] = 0
     quad[1] = 0
     quad[2] = 0
     quad[3] = 0
   Endif
   Inc n 
 Wend
   
 Return num_frame
 
End


Private Function decode_header(header As Byte[]) As Integer
 
 Dim version, layer, padding As Integer
 Dim bitrate_row, bitrate_col, sampling_row, sampling_col As Integer
 
 version = (header[1] And &08) \ CInt(2 ^ 3)     ' MPEG version
 layer = (header[1] And &06) \ CInt(2 ^ 1)       ' MPEG layer
   
 bitrate_row = (header[2] And &F0) \ CInt(2 ^ 4)
 If version = 1 Then
   If layer = 3 Then     '    I
     bitrate_col = 0
   Else If layer = 2     '   II
     bitrate_col = 1
   Else If layer = 1     '  III
     bitrate_col = 2
   Endif
 Else                    ' Versione 2
   If (layer == 3) Then2 '  I
     bitrate_col = 3
   Else If layer = 2     '  II
     bitrate_col = 4
   Else If layer = 1     '  III
     bitrate_col = 4
   Endif
 Endif
 
 sampling_row = (header[2] And &0C) \ CInt(2 ^ 2)
 sampling_col = IIf(version = 0, 1, 0)
   
 padding = (header[2] And &02) \ CInt(2 ^ 1)
   
 If sampling_matrix[sampling_row][sampling_col] = 0 Then Return -1
   
 If layer = 3 Then   '  I
   Return (12 * (bitrate_matrix[bitrate_row][bitrate_col] * 1000) / 
   sampling_matrix[sampling_row][sampling_col] + (padding * 4)) * 4
 Else If (layer = 2) Or (layer = 1)      '   II or III
   Return 144 * (bitrate_matrix[bitrate_row][bitrate_col] * 1000) /
   sampling_matrix[sampling_row][sampling_col] + padding
 Else
   Return -1
 Endif
 
End