04-20-2023, 07:29 PM (This post was last modified: 04-20-2023, 07:41 PM by mnrvovrfc.)
I have Lua code that (slowly) loads a mono 44100Hz 16-bit wave file into a table which could be split up and written to separate wave files.
However, doing it by "markers" requires being able to read chunks in the wave file. The loop point of a WAV sample is a separate chunk.
I haven't been able to completely master the ability of reading chunks beyond the "data" chunk. Also keep in mind that programs like Audacity like to save the chunk with "marker" listing before the "data" chunk. In addition, Wavosaur saves its own "saur" chunk to be able to recall a volume envelope without having to save another file that could be easily lost.
The second chunk of the file could usually be discovered after the first 40 bytes of the WAV file. The first one is "fmt " (with space as fourth character) which describes the attributes such as sampling rate, bit rate and compression technique. Compressed WAV files are a pain, need to be able to work with a codec for that. With stereo files, the difference from mono files is that the data is interlaced, ie. left side, then right side, then left side, then right side etc. I haven't looked at a WAV which has more than two channels but it should be alike, but few programs support such a thing even for 5.1 Surround sound. Dealing with 32-bit float WAV is another monster but might be necessary today, as many digital audio workstations support it.
For a QB64 program, sadly have to read the WAV file twice. Once with the programming system's means to get the sample data, and again separately in the old-fashioned way in order to go hunting for those chunks. It might be easier than expected to interpret the sample frames, taken directly from "marker" information, so that the programmer knows where in the sample data buffer to start or finish copying from.
I had to read the first post again. If it has nothing to do with "markers" already in a wave file then this should be even easier. Find the way to convert a time like 4:50 into sample frame value. IINM it should be 22050 for one second of 44100Hz sampling rate, regardless of bit rate because QB64(PE) has code to convert from a different sampling rate and perhaps from a different bit rate as well. This sample frame number is invariably needed for using with _MEMCOPY, to copy from the big WAV file into a new buffer obviously created with another _MEM variable. Could steal the WAV file header for output file but have to fill in the size of the wave file at byte position 5, and the size of the "data" chunk at the position just after that word as it appears.
EDIT: If you don't need to do this in a QB64 program, and if audiophile sound quality isn't important, convert WAV to OGG Vorbis and then use "vcut" to split:
I can write it, but I need to know what format your WAV file is in. Is it mono, stereo, 16 bit, 8 bit, 32 bit? I've worked with it quite a bit in the past. You can find the header of the WAV file in my thread, for example here https://qb64phoenix.com/forum/showthread.php?tid=1491
I would say that as long as you know how the header is formatted and can look for those tags, you should be able to split based on each occurrence of these headers. I had code for reading various music files and displaying the contents of the ID3 tags. Worked quite well, especially with FLACs that I ripped from Tidal. Those even had the lyrics and album art embedded as tags.
It looks like the OP is asking for a program that takes a text-file description, each line first with time hint and then with "song name", to tell a program how to slice a big WAV file. If the topic starter also expects the program to find the "marker" chunks in a WAV then, well, it gets more complicated for the programmer if he/she is not used to the format.
04-21-2023, 03:29 PM (This post was last modified: 04-21-2023, 03:35 PM by Petr.)
I had to try it. I only tested it on 16 bit format. stereo, but it should work on all types. The created WAV files (cut original) have the same bitrate, the same number of channels, etc., only the length is different according to the text file.
Text file format:
First line: number specifying the number of tracks to be cut
Second line: source file name in quotes
third and following lines: destination file name in quotes followed by a comma and a time in colon format (required), eg 1:25 means minute, 25 seconds.
The new file always starts exactly after the end of the previous file. For example, if you need to cut recordings with silence, write it in a text file like this (example - the source uncompressed WAV file is called allinone.wav, you want to cut it into three WAV files, with lengths of 1:10, 2:20, 3:00 but you need to cut three seconds of silence between each of these recordings) - do it like this:
then just delete created "silent" waves, tracks begin without this part.
Yes, This is really very good fun.
Code: (Select All)
'wav splitter
'STEP 1: verify text file
'text file format:
'first line is number - total files to create
'4
'next row contains wav source file name
'next 4 rows is new file name and track lenght "FileName", 0:27
'wav extension is add automaticaly
Type TrackType
Time As Single
Song As String
End Type
Type WAVHead
chunk As String * 4 ' 4 bytes (RIFF)
size As _Unsigned Long ' 4 bytes (file size) velikost souboru
fomat As String * 4 ' 4 bytes (WAVE)
sub1 As String * 4 ' 4 bytes (fmt )
subchunksize As Long ' 4 bytes (lo / hi), $00000010 for PCM audio
format As Integer ' 2 bytes (0001 = standard PCM, 0101 = IBM mu-law, 0102 = IBM a-law, 0103 = IBM AVC ADPCM)
channels As Integer ' 2 bytes (1 = mono, 2 = stereo)
rate As Long ' 4 bytes (sample rate, standard is 44100)
ByteRate As Long ' 4 bytes (= sample rate * number of channels * (bits per channel /8))
Block As Integer ' 2 bytes (block align = number of channels * bits per sample /8)
Bits As Integer ' 2 bytes (bits per sample. 8 = 8, 16 = 16)
subchunk2 As String * 4 ' 4 bytes ("data") contains begin audio samples
lenght As _Unsigned Long ' 4 bytes Data block size
End Type ' 44 bytes total
Dim WavHead As WAVHead
Dim WavNew As WAVHead
SplitTxt$ = "split.txt"
ff = FreeFile
If _FileExists(SplitTxt$) Then
Open SplitTxt$ For Input As ff
If LOF(ff) > 0 Then
Input #ff, tracks$
Tracks = Val(tracks$)
If Tracks <= 0 Then
Print "Can not create negative or zero new tracks.": End
Else
Input #ff, source$
If LCase$(Right$(source$, 4)) <> ".wav" Then source$ = source$ + ".wav"
If _FileExists(source$) Then
Dim tracks(Tracks) As TrackType
While Not EOF(ff)
Input #ff, TrackName$, TrackTime$
If LCase$(Right$(TrackName$, 4)) <> ".wav" Then TrackName$ = TrackName$ + ".wav"
tracks(ti).Song = TrackName$
separator = InStr(1, TrackTime$, ":")
If separator = 0 Then Print "Invalid track time. Use format Min:Sec": End
Min = Val(Left$(TrackTime$, separator - 1))
Sec = Val(Right$(TrackTime$, separator))
tracks(ti).Time = Min * 60 + Sec
ti = ti + 1
If ti > Tracks Then Print "Txt file contains more records than is declared on line 1 in txt file "; SplitTxt$; Tracks; ti: End
Wend
Else
Print "Source file: "; source$; " not exists.": End
End If
End If
Else
Print "File lenght "; SplitTxt$; " is not valid.": End
End If
Else
Print "File: "; SplitTxt$; " not exists."
End If
If SAFLEN < TotalTime Then Print "Source audio file is shorter than the total required length. Some audio tracks may therefore have silence at the end."
04-21-2023, 03:35 PM (This post was last modified: 04-21-2023, 03:37 PM by madscijr.)
(04-21-2023, 02:26 PM)mnrvovrfc Wrote: Welcome to the forums.
It looks like the OP is asking for a program that takes a text-file description, each line first with time hint and then with "song name", to tell a program how to slice a big WAV file. If the topic starter also expects the program to find the "marker" chunks in a WAV then, well, it gets more complicated for the programmer if he/she is not used to the format.
The source file is actually MP4 video, which I would convert to WAV (to burn to audio CD) or MP3 (for mp3 players). I asked about WAV because I don't need or want to deal with the video, and WAV is the format I want to work with for editing, and anything for working with WAV files will come in handy later!
I don't know about markers or chunks, the audio doesn't have any metadata or anything special (such as what a DAW might add or use), all I have is a separate text file with the track title listing with each track's length. Slicing up the file automatically would be nice, but actually the track times might not account for any space between songs (I'd need to check when back at the PC), and if that's the case, then I would have the program go to the end of the first track and search forward to determine when the next track begins. The track times can be used as guides, but the actual begin and end locations are approximate, if they don't include the blank space at the end of each track.
I did google some more and found a ton of Python scripts that split up sound files, using whatever Python libraries for working with WAV and MP3. QB64PE doesn't have any WAV or MP3 file libraries that I'm aware of, so I think I would need to write all the code to handle reading/parsing/processing/writing the files.
As bplus said (and I already figured) the first step is to study the WAV file spec, which I will do as I have time, but I figured it can't hurt to ask here and see if there is any pre-existing QB-like code I could reuse or study to figure out how to do this.
(I could always just use Python, but where would the fun be?? LoL)
04-21-2023, 03:46 PM (This post was last modified: 04-21-2023, 03:58 PM by mnrvovrfc.)
From MP4 it might be possible with FFMPEG but the command-line syntax is very complicated and convoluted.
At around this time last year LOL I downloaded the first six episodes of "Silver Moon" Anime cartoon series from "archive-dot-org". It was slow, over six hours! It came as a bunch of VOB files that I had to put together into a single MP4 file using FFMPEG on Windows. But that's putting together the pieces, not taking the big one apart! I'm saying this because it should be possible to get smaller WAV files out of a single MP4, but the utility to do it is difficult to deal with for the average user. Because you want audio only it's easier than video to video.
As I've said in my first post in this topic, all it requires is parsing the time, from the text file that you provided as input, then find the way to turn that into a sample frame number. Then just use _SNDOPEN() to load the WAV, use _MEMSOUND() to get a _MEM variable for it, then allocate another _MEM variable [not necessary to use the new syntax for _SNDOPEN() because there's no direct way to save that to disk] for the output buffer to hold a piece of the large sample data buffer. Could use _MEMGET and _MEMPUT for the "slow" way, or if you know what you are really doing, could just use _MEMCOPY with the right size of one song from the sample data. Adding silence at front or back is up to you, will require additional programming (trickery) but not really that difficult. I wish I could cobble up an example for you.
Doing sample markers inside a WAV isn't going to get the names of the songs in many cases. It depends on a WAV prepared by the original author, or if conversion to WAV was able to go that far. That's why "your way" is better: I give you a wave file and a text file for how to chop it up. LOL.
EDIT: I had ignored Petr's contribution. That should be enough. Just fix it for the sake of absolute elapsed times over the big wave file.