Search code examples
c++qtbass

C++ char* relative file path? (Qt)


I am trying to play a .mod audio file in an executable. I am using the 3rd party BASSMOD .dll. I can get the audio file to play when I provide the full path to the file, but I cannot get it to play when providing a relative path. Here are some snippets.

main.cpp

#include <QCoreApplication>
#include "bassmod.h"

// define file location
const char* file = "C:/Users/Downloads/test4/console/music.mod";

void startMusic() {
  BASSMOD_Init(-1, 44100, 0);
  BASSMOD_MusicLoad(FALSE,(void*)file,0,0,BASS_MUSIC_RAMPS);
  BASSMOD_MusicPlayEx(0,-1,TRUE);
}

int main(int argc, char *argv[])
{
  QCoreApplication a(argc, argv);
  startMusic();
  return a.exec();
}

bassmod.h (relevant snippet)

BOOL BASSDEF(BASSMOD_MusicLoad)(BOOL mem, void* file, DWORD offset, DWORD length, DWORD flags);

The function I'm concerned about is BASSMOD_MusicLoad. As this project stands, the .mod file will play no problem. However, when I try to change the absolute path of the .mod file to a relative path ("music.mod"), the file fails to play. Why is that? I have the .mod file in the same directory as the executable as well as in the directory containing the .pro file -- that didn't seem to be the issue.

Also, maybe I'm missing something related to how files are opened in C++. It looks like the MusicLoad function requires that the second parameter be of type void*. I'm sure there are many different things I could be doing better here. Ideally, I'd like to be able to have file store the relative path to the .mod file and have it play that way so I don't have to hard code an absolute path. In a perfect world, I would like to supply file with a path to the .mod file in my resources.qrc, but then I would have to use QFile, I believe, which won't work because I need the type to be void*.

Any help for a beginner would be much appreciated.


EDIT 01: Thank you all for your help! I got it to work (using relative file path, at least). There are two ways to do this. Here's what I did and how I tested it:

The first case makes the assumption that BASSMOD (or whatever external dll you're using) does not handle relative paths.

const char* file = "C:/debug/music.mod"; // same dir as .exe
QFileInfo info("music.mod");
QString path = info.absoluteFilePath();
const string& tmp = path.toStdString();
const char* raw = tmp.data();

Those are the test items I set up. When I run BASSMOD_MusicLoad(FALSE,(void*)file,0,0,BASS_MUSIC_RAMPS);, it works as expected. That's when I hard-code the full absolute path.

When I ran BASSMOD_MusicLoad(FALSE,(void*)raw,0,0,BASS_MUSIC_RAMPS);, it didn't work. So I decided to print out the values for everything to see where it's messing up:

 cout << "Qstring path: ";
 qDebug() << path;
 cout << "string& tmp: ";
 cout << tmp << endl;
 cout << "raw: ";
 cout << raw << endl;
 cout << "full char* file: ";
 cout << file;
 startMusic();

...returns this:

Qstring path:
"C:/myApp/build-Debug/music.mod"
string& tmp:
C:/myApp/build-Debug/music.mod
raw:
C:/myApp/build-Debug/music.mod
full char* file:
C:/myApp/build-Debug/debug/music.mod

Note the difference? When I hard-code the full path to the file, I found that (thanks to @FrankOsterfeld and @JasonC) the current working directory was actually not where the .exe (/debug) or .pro files were located. It was actually in the same directory as the Makefile.

So I just changed it to this: QFileInfo info("./debug/x.m"); and it worked.

Even though the problem wound up being me not knowing where the current working directory was, the solutions by @Radek, @SaZ, and @JasonC helped to find another way to solve this (plus it showed me how to get the working dirs and convert between types). This is a good reference for people who would want to use QFileInfo to determine where you actually are in the filesystem. I would have used this solution if the dll I was using did not handle relative paths well. However...

I wondered if I could apply the same solution to my original code (without using QFileInfo and converting types, etc). I assumed that BASSMOD did not handle relative paths out of the box. I was wrong. I changed the file variable to const char* file = "./debug/x.m"; It worked!

Thanks for the help, everyone!

However, I would still like to get this to work using music.mod from a Qt resources file. Based on the replies, though, it doesn't look like that's possible unless the 3rd party library you're using supports the Qt resource system.


Solution

  • I have the .mod file in the same directory as the executable.

    In Qt Creator the default initial working directory is the directory that the .pro file is in, not the directory that the .exe ends up in.

    Either put your file in that directory (the one that probably has all the source files and such in it as well, if you used the typical setup), or change the startup directory to the directory the .exe file is in (in the Run Settings area).

    Although, based on your new comment below, I guess the problem is deeper than that... I can't really tell you why BASS doesn't like relative filenames but you can convert a relative path to an absolute one before passing it to BASS. There's a lot of ways to do that; using Qt's API you could:

    #include <QFileInfo>
    
    ...
    const char* file = "music.mod";  // Your relative path.
    ...
    
    BASSMOD_MusicLoad(...,
                      (void*)QFileInfo(file).absoluteFilePath().toAscii().data(),
                      ...);
    

    In a perfect world, I would like to supply file with a path to the .mod file in my resources.qrc

    You won't be able to do that because loading resources from .qrc files is a Qt thing and BASS presumably does not use Qt internally (just like e.g. you could not open a resource with fopen), and doesn't understand how to load resources embedded by Qt. I am not familiar with BASS but a cursory glance at this documentation shows that it also has the ability to play data from an in-memory buffer. So one approach would be to use Qt to load the resource into accessible memory and pass that buffer instead.