Need help with DTS file conversion!

Started by siggi,

siggi

Hello everybody!

I'm trying to add some new file types to my AudioZip application to support playback, tagging
and conversion to other audio formats. Already managed a lot of new formats like TAK, Opus, Midi etc. but I'm really stucked with DTS!  :-[

I'm using BASS 2.4.15 which works fine for all my needs. I use Delphi.

Downloaded the inofficial bass_dts.dll without the Delphi .pas dated from 18.10.22 which allowed playback and tagging
after coding my own Delphi pas file to access the BASS_DTS_StreamCreateFile inside that DLL.

My problem now is related to encoding DTS to other formats like wav,mp3,wma,ogg,wv or ape.
The ape codec always gives out empty files, others work now.

More problems with splitting DTS and reencoding... All codecs don't receive the correct byte position to split the files.
I really don't know much about Home Cinema Formats as is DTS!

My 3 test files have different sample rates and channel numbers. 44100/6, 48000/6 and 96000/6.
I can't set the correct byte position in the decoder/mixer stream.

There are more functions inside the bass_dts.dll which are listed here after using a DLL-Viewer :
1 (0x0001),  (0x), BASS_DTS_CanSetPosition, 0x00001c20, None
2 (0x0002),  (0x), BASS_DTS_Free, 0x00001d10, None
3 (0x0003),  (0x), BASS_DTS_GetInfo, 0x00001bf0, None
4 (0x0004),  (0x), BASS_DTS_GetLength, 0x00001b90, None
5 (0x0005),  (0x), BASS_DTS_SetPosition, 0x00001c50, None
6 (0x0006),  (0x), BASS_DTS_StreamCreate, 0x000018d0, None
7 (0x0007),  (0x), BASS_DTS_StreamCreateFile, 0x000019f0, None
8 (0x0008),  (0x), BASS_DTS_StreamProc, 0x00001a60, None
9 (0x0009),  (0x), BASS_DTS_StreamWrite, 0x00001b40, None
10 (0x000a),  (0x), BASSplugin, 0x000018a0, None

I could not manage to extract them to the Delphi .pas file as I don't know their types and vars.
Maybe they could solve my problem!

So, my questions:
Anybody knows about a working  Delphi pas file for that DLL?
Anybody can point me to what I'm not considering?
Anybody has experiencies with that unofficial DLL? Did it ever work?
Should I migrate to the latest BASS version?
Any other suggestions?

If needed I can submit some code sequencies..

Thanks in advance!


Chris

This lib is 4 years old.

but the dts lib is not compatible with the newest Bass Version.
eg
Bass :  BASS_StreamCreateFile(filetype: DWORD; f: Pointer; offset, length: QWORD; flags: DWORD): HSTREAM;
while
Bass_dts BASS_DTS_StreamCreateFile)(mem:boolean; f: Pointer; offset, length: QWORD; flags: DWORD):HSTREAM;
by the way you can try
just load the lib via Bass_PluginLoad.....
then access all needed calls directly from bass.
Bass_DTS Source (c++)

Ian @ un4seen

Although it's quite old, that BASS_DTS.DLL should actually still be compatible with the latest BASS version because the "mem" to "filetype" parameter change was done in a back-compatible way (BASS_FILE_MEM=TRUE) and the add-on just forwards that value to BASS. It looks like BASS_DTS.DLL is exporting internal functions that shouldn't be used directly. You can ignore those and stick with BASS_DTS_StreamCreateFile.

If you're only having a problem with the APE encoder then it seems like there's something specific about that. Are you using it with BASS_Encode_Start? If so, you could try BASS_Encode_StartLimit instead with the "limit" parameter set to the DTS stream's length (from BASS_ChannelGetLength), so that the encoder is told in advance how much data there will be.

siggi

Hi Chris,
Thanks for replying!

Just opened the link but have some doubts, as I'm used to Delphi.
These 2 functions could change the thing...

QWORD BASSDTSDEF(BASS_DTS_SetPosition)(void* inst, QWORD position, DWORD mode);
QWORD BASSDTSDEF(BASS_DTS_GetLength)(void* inst, DWORD mode);

But the declaration void* inst is not clear. What is expected here?
A pointer to the HStream? What can be "inst"?
And I don't know the possible values for "mode"...
Maybe there are special ones in the DLL..

Other thing: There is no comparable function in BASS for this function
BOOL BASSDTSDEF(BASS_DTS_CanSetPosition)(void* inst, QWORD position, DWORD mode);
What is this for?

Anyway I can try to add the first 2 functions to my Delphi pas file this evening
taking the HStream for "inst" and see if it works...

Have a good day!

siggi

Hi Ian,
Til now I only use the function BASS_DTS_StreamCreateFile from the DLL which works fine.

The BASS function BASS_ChannelStreamCreateFile gave strange problems as the stream never got completely
freed! My own application blocked the file so I could not access to it to write a new TAG..
My own integrated Unlocker showed up to 20 different process handles blocking the affected file
(Other external Unlocker the same).
This problem got off after using BASS_DTS_StreamCreateFile.

But the problem splitting a DTS file happens with any of my integrated codecs.

My code now looks like this:
//Creating stream and mixer
if fext = '.dts' then
                decoder:= BASS_DTS_StreamCreateFile(0, PwideChar(filepath), 0, 0, BASS_STREAM_DECODE or BASS_STREAM_PRESCAN or BASS_UNICODE)
               else
                 decoder:= BASS_StreamCreateFile(FALSE, PwideChar(filepath), 0, 0, BASS_STREAM_DECODE or BASS_STREAM_PRESCAN or BASS_UNICODE);
                  //para los wma y ogg!! resample y stereo
                  mixer:= BASS_Mixer_StreamCreate(44100, 2, BASS_MIXER_END or BASS_STREAM_DECODE); // create mixer
                  BASS_Mixer_StreamAddChannel(mixer, decoder, BASS_MIXER_NORAMPIN); // plug decoder into mixer

I tried also to set the sample rate and Channel in StreamAddChannel as read out before, no change!
//Setting startpos and limit, checking startpos by showmessage
// here is a mixup just now between decoder and mixer, I tried any configuration without success!
startpos:= BASS_ChannelSeconds2Bytes(decoder, albumarray.start);
                         showmessage(inttostr(round(albumarray.start)));
                  BASS_ChannelSetPosition(mixer, StartPos, BASS_POS_BYTE);
                  startpos:=BASS_ChannelGetPosition(decoder, BASS_POS_BYTE);
                   showmessage(inttostr(round(BASS_ChannelBytes2seconds(mixer, startpos))));
                  if (cbformato.Itemindex = 2) {or (cbformato.Itemindex = 4)} then
                   limit:= BASS_ChannelSeconds2Bytes(mixer, albumarray.time)
                  else
                  begin
                    limit:= albumarray.bytesize; //bytesize mas exacto con BASS_STREAM_PRESCAN-flag en BASS_StreamCreateFile

//Setting the encoder, now to the mixer channel else nothing works with DTS!
case cbformato.Itemindex of  //set encoder
                  0: begin  //wave
                      BASS_Encode_Startlimit(mixer, PChar(destpath), BASS_ENCODE_PCM or BASS_ENCODE_AUTOFREE or BASS_UNICODE, nil, nil,limit);
                     end;
                  6: begin  //ape/mac no trabaja bien con Unicode,truco con dummypath! dummydir porque Win7 no deja crear archivos en C:
                      dummydir:= drive+'\dummy';
                      if wideCreateDir(dummydir) then
                       dummypath:=dummydir + '\dummy' + ext;
                      param:= exedir+'codecs\mac.exe - "' + dummypath + '" ' + apeparam;
                      BASS_Encode_Startlimit(mixer, PChar(param), BASS_ENCODE_AUTOFREE or BASS_UNICODE, nil, nil, limit);
                     end;
                  end; //case set encoder
//the APE codec produces here files with content but not readable!
//the WAVE and all other codecs bring out the first split part of 1 min. correctly
//but the second part always starts some seconds too early and cuts off at the end!
So the setposition function seems not to work with DTS neither on decoder nor on mixer stream!

Hope I have clarified a bit more the problem...

Cheers!

siggi

Hi Ian,
Sorry for the mismatch between Decoder and Mixer Channel, I spent many hours trying too much different things!

Remarkable;
In the section //Setting startpos and limit the startpos is with the supplied code snippet
0 for the first split and 60 sec for the second one. This would be correct as I devided
the file in 2 parts after 60 sec.

Before I set the startpos on the decoder channel And got back 20 sec for the second part.
This was clearly wrong, but both settings result as the same.

Can't pick the logic of the problem!

Ian @ un4seen

In the BASS_DTS source code, it looks like it just calculates an approx file offset from the requested seek position and decoding resumes from the next DTS frame after that in the file. So the actual position may be up to a frame ahead of the requested position, assuming that the file has a constant bitrate. If it's variable bitrate then the difference may be even more!

    https://github.com/pudding-fox/BASS_DTS/blob/37604669600bcdd64478fdbb5718a47a2f6dd299/bass_dts/bass_dts.c#L202

For precise seeking, you could use the BASS_POS_DECODETO flag in your BASS_ChannelSetPosition call. Note that can only go forwards. If you need to go backwards then seek to 0 first.

siggi

Hi Ian,
Interesting! But I don't use the BASS_DTS function to set position, only the native BASS one.
Pudding-Fox devides the bytes by channel numbers... Strange but worth to think about!
IN MY CASE THE OFFSET IS TOO EARLY.

I will rethink everything as soon as I can and make new trials.

Ian @ un4seen

Quote from: siggiBut I don't use the BASS_DTS function to set position, only the native BASS one.

Yes, the usual BASS functions (eg. BASS_ChannelSetPosition) are used on the stream once it's been created. Only the stream creation uses an add-on function for a specific file format (DTS in this case). The same thing can be seen with other add-ons (BASSFLAC/etc).

siggi

Hi Ian,
Just to tell that finally I'll descard supporting DTS after spending again a whole day
on this problem!

It's more, I noticed that the positions of the progress bar for playback in my main
window also are not correct! Didn't see it before!

The length of my 4 test files is incorrect, so the music ends before the progreaa bar reaches
the end.
Just to show the differences and comparing to VLC MediaPlayer:

Samplerate/channels       AudioZip   VLC/Win10      VLC/WinXP old version

File1 44100/6 RIFF HEADER 2:57/2:47  2.47/2:47      2:56/2:46    returned length/end of sound
file2 56000/6             6:51/6:46  6:52/6:52      6:57/6:52
file3 96000/6             4:30/4:22  4:26/4:26      4:34/4:25
file4 44100/6             2:19/2:20                 2:38/2:38

These results are quite weird! A difference of 1 sec is due to rounding.
Only the newest version of VLC gives accurate values. Dont have other programms supporting DTS.

For playback only I tried working only with a play channel with and without mixer channel,
tried also the Functions BASS_DTS_GetLength and BASS_DTS_SetPosition without luck!

As AudioZip is for real music lovers, not for Surround freaks I can live without DTS!
Me, I never have been to a concert surrounded by Musicians  ;D

Nevertheless it would be nice if anybody could bring a light to this strange technic, I've not
the time to study this thing deeply.

Thanks for all replies!

siggi

Hi again,
I could not sleep well and tried a little more... :D

I tested again around with the code just for playback.
I have a function to check each audiofile for validity, from there I get all info like
length, samplerate, bitrate etc.

Here the relevant code snippet:

if ex = '.dts' then
    chan:=BASS_DTS_StreamCreateFile(0, pwidechar(fileName), 0, 0, BASS_STREAM_DECODE or BASS_STREAM_PRESCAN or BASS_SAMPLE_FLOAT or BASS_UNICODE)   else
  else
   Chan := Bass_StreamCreateFile(false, PwideChar(FileName), 0, 0,Bass_Stream_Decode or BASS_STREAM_PRESCAN or BASS_SAMPLE_FLOAT or BASS_UNICODE);
            showmessage(inttostr(chan)); //gives a chnnel number
            showmessage(inttostr(BASS_ErrorGetCode()));  //code 0
  if Chan <> 0 then //file contains audio supported by  BASS
  begin
    //read attributes
    leng:= BASS_ChannelGetLength(Chan,BASS_POS_BYTE);
        showmessage('getlength' +inttostr(BASS_ErrorGetCode()));  //code 5 = BASS_ERROR_HANDLE WHY?????
    BASSInfo.playtime:=BASS_ChannelBytes2Seconds(Chan,BASS_ChannelGetLength(Chan,BASS_POS_BYTE));
        showmessage('bytestosec'+inttostr(BASS_ErrorGetCode()));  //code 0!!! why not code 5 as before???

Here the first getlength function returns Error Code 5 on the DTS channel! The returned length is slightly more than expected.See the differences in my last post.
The second getlength function inside ChannelBytes2Seconds returns no Error.
Can you explain this?

Could not get to work the Bass_DTS_getLength function from the DLL to test with!

Another thing I can't explain:

When I use Bass_StreamCreateFile with DTS files the channel never gets freed!
No Error is returned but the file is blocked after BASS_ChannelFree!
I played around with Bass_ChannelLock set to false but no luck.
The getlength function in this case returns the exact length!
As well would the functions setposition and getposition.

These 3 functions must work to play DTS with a correct progress bar, and of course for encoding and splitting.

Any ideas? I hate giving up! 8)
 

Chris

Hi i just will have here not any dts File .
Can you upload them anywhere ? The I can do here some tests in Radstudio 13.
Chris

Chris

#12
Hi, so first i think it`s not recommend to filter a File by its extension.
Because there is no guaranty that the FileExt is the correct Filetyp.
By the way i have made here a modified Demo of the Plugins Demo (Delphi13) (a DTS File is include) with DTS
and all will looking fine.
In this demo the DTS Lib (bass_dts.dll) was load via Bass_PluginLoad .
Also Bass_StreamFree looks good.
You can download it here
Just try it with your own DTS Files.   

siggi

Hi Chris,
Thanks for the demo, just tried it!

I can see that you use the native BASS_StreamCreateFile function.
It does not get freed! You free the Stream when loading again a file.
So I loaded the same test file 3 times and got 3 handles on it!
This is why I can't use that function in AudioZip, because the file keeps locked
and it is not possible to do other things with it like writing TAGs etc.
Nevertheless the length and positions are accurate using BASS_StreamCreateFile.

Here a screenshot showing my own Unlocker, same result by other external Unlockers.

image(edit).jpg

siggi

By the way, I don't just filter files by extension.

I have a special function in AudioZip called IsValidBassAudio which checks the filetype and offers
valid file extensions if file has wrong extension. This can be corrected then by the user with 1 click!

Even there every DTS file gets locked when using BASS_StreamCreateFile, because it does not get freed!

siggi

Addition:

Of course you only can reproduce this when you have an Unlocker tool at hand or when you try to
do something with the locked file inside your Demo requiring write access.

There is a tool for XP called simply Unlocker but does not work an newer systems.
I always test my App on several Windows versions including the old and stable XP!

The blocking only occurs with DTS files and BASS_StreamCreateFile!
BASS_DTS_CreateFile does not block but returns weird length and positions which seem to have no logic.
At least I can't see it!

Chris

#16
Hm i can that not confirm.
Doing here another Test on the demo
Just Place on the Form a simple Button with the following Code:
procedure TForm1.Button2Click(Sender: TObject);
begin
  Timer1.Enabled := False;
  BASS_ChannelStop(Chan);
  if not BASS_StreamFree(Chan) then
    Error('Error, Can`t free the Stream');
  if not RenameFile(progdir + 'testfile.dts', progdir + 'rename_testfile.dts') then
    ShowMessage('Error, Can`t rename the File');
end;

it will correct Freeing and renaming the File will working without any Problems.
I have tested that with win7,win10,win11 (delphi13)

----------------------
Here is another Demo (without plugin stuff just with BASS_DTS_StreamCreateFile )
will returning also the correct length
Demo

siggi

Hi Chris,

Many thanks for the interest in my problem!
You're doing a great job!

I will check the new information as soon as I can.
Today I'm too tired yet! Have been working on other parts of my code.

Tomorrow I'll tell you!

Falcosoft

Quote from: siggiAddition:

...
There is a tool for XP called simply Unlocker but does not work an newer systems.
I always test my App on several Windows versions including the old and stable XP!

...

There is a free tool with the same unlocking functionality for newer systems:
https://lockhunter.com/?ver=3.4.3.146&ostype=win64&sm=main_window_64

Chris

#19
So after some long testing
i can confirm that the FileHandle of a DTS AudioFile is not correctly freed if working with the Bass PluginSystem.
if creating a stream via BASS_DTS_StreamCreateFile then the DTS FileHandle is correctly freed.
with other Addons (tested with opus,aac) all is fine.

siggi

Ok Chris,
that is what I experimented!

I noticed you are using a newer BASSversion, I am on 2.4.15 .
Soon i'll compare our BassDTS versions and our DTS files.
I've one which gives correct length using BASS_DTS_StreamCreateFile,
others don't.

The functions Getposition and Setpositio don't match the length so.
They are of different sample rates, Maybe this brings the problem...

Ian @ un4seen

Quote from: Chrisi can confirm that the FileHandle of a DTS AudioFile is not correctly freed if working with the Bass PluginSystem.
if creating a stream via BASS_DTS_StreamCreateFile then the DTS FileHandle is correctly freed.

I see that's caused by a little bug in the BASS_DTS code here:

    https://github.com/pudding-fox/BASS_DTS/blob/37604669600bcdd64478fdbb5718a47a2f6dd299/bass_dts/bass_dts.c#L117

The SetStream call should be at the end of the BASS_DTS_StreamCreate function instead of the BASS_DTS_StreamCreateFile function. Because it isn't called in BASS_DTS_StreamCreate, that means the file is never closed when using the plugin system.

But I don't think DTS files are generally playable via the plugin system anyway, because they usually have normal PCM WAV headers? So BASS would treat them as normal PCM WAV files and play them itself (producing noise unless you have a DTS receiver to decode it).

siggi

#22
Hi Ian,
You are mixing up things!

When using BASS_DTS_StreamCreateFile from the plugin then freeing IS CORRECT!!
Using BASS_StreamCreateFile on DTS blocks the file!

DTS files DO NOT have usually PCM WAV headers!
I have now 5 different DTS files, only one has a PCM WAV Header which when played
with BASS_StreamCreateFile produces only noise.
All others play fine.

With BASS_DTS_StreamCreateFile all play fine, but the returned length is only correct with files
of 44100 sample rate.

Just now I'll post to Chris my latest results.

siggi

#23
Hi Chris,

Our Bass_DTS DLLs seem to be the same. I got 2 others from around Internet with
different sizes, both don't work.

I tested my 4 DTS files and yours with both of your demos for their length.
Here the result:

        SampRate/Channels       'plugins'   'dts-demo'
file 1  44100/6 PCM/WAV Header   2:47        2:57
file 2  46000/6                  6:46        6:51
file 3  96000/6                  4:22        4:30
file 4  44100/6                  2:19        2:19   
yours   44100/2                 12:08       12:08

As we see here only the last 2 files with sample rate of 44100 have the same length in both demos.
The first file with PCM/WAV Header and 44100 makes the exception.
the other 2 files with different sample rate show big differencies!
Your file is stereo, don't know why somebody put this into a DTS file...

You can find the first 3 files in https://github.com/pudding-fox/BASS_DTS/tree/main/Media

Resuming:
When I would continue to work with BASS_DTS_StreamCreateFile I would need to solve the problem
withh the incorrect length.
To continue with BASS_StreamCreateFile someone must explain the freeing problem!

Thanks til now to all posters!

Ian @ un4seen

Quote from: siggiWhen using BASS_DTS_CreateFile from the plugin then freeing IS CORRECT!!
Using BASS_StreamCreateFile on DTS blocks the file!

Yes. To clarify, the "plugin system" means using BASS_PluginLoad to plug add-ons (eg. BASS_DTS) into BASS_StreamCreateFile. When you use BASS_DTS_StreamCreateFile, you aren't using the plugin system (you're using BASS_DTS directly). So it is correct to say that the file locking problem only happens when you use the plugin system (due to the missing SetStream call that I mentioned).