Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: String, Dstring, and Char[] oh my...  (Read 8397 times)

0 Members and 1 Guest are viewing this topic.

malkierian

  • Newbie
  • *
  • Posts: 39
    • View Profile
String, Dstring, and Char[] oh my...
« on: December 20, 2013, 03:50:23 am »
OK, so I'm trying to use SFML's Audio module to play a sound, and I'm using the Windows headers to open the file (default Windows file dialog).  SoundBuffer.loadFromFile takes a "string" argument.  The Windows file dialog process takes a char[] array, and I am trying to use the return I get from the file select window to also form the default "tag", or in-program identifier, as a label as part of a sound actor class (custom class that handles play, stop and open buttons for a group, as well as the label), which also means I need to use a substring of the file name returned from the file select.  So essentially I need to go from char[] to string, and char[] to sub-dstring.  But I keep getting this error after picking the file and trying to load it:

std.utf.UTFException@E:\Dlang\dmd2\windows\bin\..\..\src\phobos\std\utf.d(1113): Invalid UTF-8 sequence (at index 1)

I am running the file selector in a separate function.  I have tried passing a pointer argument to the function to return through, and I've tried returning it directly, both fail.  How do I properly return a string/dstring argument from a function, and how do I properly/effectively convert between those three formats?

Jebbs

  • Sr. Member
  • ****
  • Posts: 358
  • DSFML Developer
    • View Profile
    • Email
Re: String, Dstring, and Char[] oh my...
« Reply #1 on: December 20, 2013, 04:59:25 am »
The string type is really just an alias for an array of immutable characters(immutable(char)[]). A really easy way to go from a char[] to a string is to make a copy of the array but with immutable data using idup.
char[] str1 = "String Literal!".dup;//make a mutable copy of the string literal
string str2 = str1.idup; //make a copy of the array with immutable data  

If you ever need to go to a char[] from a string, you can use std.conv's to function.
import std.conv;
string str1 = "String Literal!";
char[] str2 = to!(char[])(str1);

Is there any reason you need your substring to be a dstring? Why not also make it a string as well and just use a slice?

DSFML - SFML for the D Programming Language.

malkierian

  • Newbie
  • *
  • Posts: 39
    • View Profile
Re: String, Dstring, and Char[] oh my...
« Reply #2 on: December 20, 2013, 05:42:49 am »
Is there any reason you need your substring to be a dstring? Why not also make it a string as well and just use a slice?
I guess I may not have been clear enough in my original post, but SoundBuffer.loadFromFile() uses string, while Label.setString uses dstring, and neither will accept the other format.

EDIT: The biggest issue is that the Label.setString is the one I need to slice into, and that's what needs the dstring.  And when I try to do it (ala
Code: [Select]
label.setString(to!dstring(temp[(temp.lastIndexOf('\\') + 1)..(temp.length)].dup)); I get this error:
Code: [Select]
std.utf.UTFException@E:\Dlang\dmd2\windows\bin\..\..\src\phobos\std\utf.d(1113): Invalid UTF-8 sequence (at index 1), and I've already tested that setString works with a literal, and that slice actually works, believe it or not.  But when converting that slice to a dstring, if fails with that error I already mentioned.
« Last Edit: December 20, 2013, 06:13:39 am by malkierian »

Jebbs

  • Sr. Member
  • ****
  • Posts: 358
  • DSFML Developer
    • View Profile
    • Email
Re: String, Dstring, and Char[] oh my...
« Reply #3 on: December 20, 2013, 06:12:59 am »
It'll be hard to get this exactly right with out seeing any code, but you should be able to get the idea from the following pseudocode.
import std.conv;
char[] fileToLoad = getFileNameFromFilePicker();
audioBuffer.loadFromFile(fileToLoad.idup);
audioLabel.setString(to!(dstring)(fileToLoad[start..end]));

Hope that works for ya!
DSFML - SFML for the D Programming Language.

malkierian

  • Newbie
  • *
  • Posts: 39
    • View Profile
Re: String, Dstring, and Char[] oh my...
« Reply #4 on: December 20, 2013, 06:33:00 am »
Yeah, I think I edited my post after you replied.  I've tried that and it doesn't work.  It doesn't seem to work with anything but a literal.

EDIT:  After some creative Google searching, it seems that this is more a Dlang issue than it is an SFML issue.  Could there be something wrong in your binding that's causing it?
« Last Edit: December 20, 2013, 07:06:46 am by malkierian »

Jebbs

  • Sr. Member
  • ****
  • Posts: 358
  • DSFML Developer
    • View Profile
    • Email
Re: String, Dstring, and Char[] oh my...
« Reply #5 on: December 20, 2013, 07:22:23 am »
label is a Text instance, yes? I can't seem to reproduce the problem. Can you make a minimal example that reproduces the same issue?
DSFML - SFML for the D Programming Language.

Jebbs

  • Sr. Member
  • ****
  • Posts: 358
  • DSFML Developer
    • View Profile
    • Email
Re: String, Dstring, and Char[] oh my...
« Reply #6 on: December 20, 2013, 07:59:46 am »
EDIT:  After some creative Google searching, it seems that this is more a Dlang issue than it is an SFML issue.  Could there be something wrong in your binding that's causing it?

That could very well be the case, and is probably the most likely thing :P. If I can track it down I would be happy to get it fixed, but if I had a minimal example then it would be much easier.
DSFML - SFML for the D Programming Language.

malkierian

  • Newbie
  • *
  • Posts: 39
    • View Profile
Re: String, Dstring, and Char[] oh my...
« Reply #7 on: December 21, 2013, 01:57:21 am »
Oh my gosh, I think I figured it out.  So the file open dialog stuff is as follows:

auto openSoundFile()
{
        char[256] filenameBuffer;
        filenameBuffer[0] = 0;
        OPENFILENAME info;
        info.lStructSize = OPENFILENAME.sizeof;
        info.lpstrFilter = "Audio Files\0*.wav;*.ogg\0\0".ptr;
        info.lpstrFile = filenameBuffer.ptr;
        info.nMaxFile = filenameBuffer.length;
        if(GetOpenFileNameA(&info))
        {
                return to!string(filenameBuffer);
        }
        else return to!string("!!failed");
}

Apparently returning that as a string returns the entire char array, including the garbage after the file path, which my slice (temp.length - 1) then pulled for some reason.  Here's the code I'm using so you can at least try to debug if it's an issue in DSFML:

http://pastebin.com/Xfr53gNu

By the way, although the Text.setString works now, the program always stops responding when I uncomment the part for loading the SoundBuffer and I'm not sure why.

Jebbs

  • Sr. Member
  • ****
  • Posts: 358
  • DSFML Developer
    • View Profile
    • Email
Re: String, Dstring, and Char[] oh my...
« Reply #8 on: December 21, 2013, 02:14:38 am »
Cool. I should be able to get to this either tonight or tomorrow. I'll let you know when I have something!
DSFML - SFML for the D Programming Language.

malkierian

  • Newbie
  • *
  • Posts: 39
    • View Profile
Re: String, Dstring, and Char[] oh my...
« Reply #9 on: December 21, 2013, 03:41:35 am »
Update:  If I feed the loadFromFile function a lstring literal, it still freezes the program.  This is a valid WAV file I'm trying to load, not even an Ogg.

malkierian

  • Newbie
  • *
  • Posts: 39
    • View Profile
Re: String, Dstring, and Char[] oh my...
« Reply #10 on: December 23, 2013, 01:07:55 am »
By way of bumping, I just wanted to report that Ogg files don't work with that code I posted either.  Same freezing.  Also, the message I get in console is

Stream closed?
Stream closed?

Yes, I get it twice for one file operation.

malkierian

  • Newbie
  • *
  • Posts: 39
    • View Profile
Re: String, Dstring, and Char[] oh my...
« Reply #11 on: December 23, 2013, 06:27:52 am »
And another development arrives.

So I tried adding a try...catch around my call to SoundBuffer.loadFromFile(), and while it is obviously erroring (I put an error message in there) since I caught the error, it actually goes on to load and play the sound fine.  I have no freaking idea what's going on at this point.

Here's the most basic code you could want to test it:
module main;

import dsfml.audio;
import dsfml.graphics;
import dsfml.window;

import std.stdio;

void main(string[] args)
{
//      new Soundboard().run();
        auto window = new RenderWindow(VideoMode(1280, 720), "Virtual Soundboard", Window.Style.Titlebar | Window.Style.Close);
        auto buffer = new SoundBuffer();
        auto sound = new Sound();
        writeln("Buffer and Sound instantiated");
        try
        {
                if(!buffer.loadFromFile("F:\\Soundboard\\Ogg\\AirLeak.ogg"))
                        return;
                writeln("Buffer loaded");
        }
        catch
        {
                writeln("Error loading file to buffer");
        }
        sound.setBuffer(buffer);
        sound.play();
        while (window.isOpen())
        {
                Event event;
                while(window.pollEvent(event))
                {
                        if(event.type == Event.EventType.Closed)
                        {
                                window.close();
                        }
                }
               
                window.clear(Color.Black);
               
                window.display();
        }
}
Just put in whatever sound file you want for the buffer and try commenting the try...catch.  It'll freeze.  But with it in there, it tells you in the console that there was an error loading the buffer (which I believe, if you run it without the try catch, it will tell you is an access violation in that line), but then successfully plays it before starting the main loop.

EDIT: This hack only seems to work for OGG files.  Try to do that with a WAV and it will still freeze the program.  And when the OGG file continues, it actually gives a core.exception.InvalidMemoryOperationError instead of an access violation.  This is extremely weird...

EDIT 2:  Even with that hack, it doesn't work every time, and I can't track down why not.

EDIT 3:  ACK!  It appears that every fifth time I run the program it works, and every now and then it will even load WAVs on that successful run.  WHAT THE HECK IS GOING ON?!  LOL.  This is so perplexing.
« Last Edit: December 23, 2013, 07:02:59 am by malkierian »

Jebbs

  • Sr. Member
  • ****
  • Posts: 358
  • DSFML Developer
    • View Profile
    • Email
Re: String, Dstring, and Char[] oh my...
« Reply #12 on: December 23, 2013, 10:08:16 pm »
I just started vacation from work today, so you can expect me to dig into this very soon!

Also, the message I get in console is

Stream closed?
Stream closed?

Yes, I get it twice for one file operation.

Yikes! Looks like I had testing code still present in the libs I sent you before. I doubt this will fix your problem, but at the very least use the new ones I recently posted links to in the nightly thread.
DSFML - SFML for the D Programming Language.

Jebbs

  • Sr. Member
  • ****
  • Posts: 358
  • DSFML Developer
    • View Profile
    • Email
Re: String, Dstring, and Char[] oh my...
« Reply #13 on: December 24, 2013, 09:27:54 am »
So, using the nightly DSFML-C build and modifying parts of your code, it worked fine for me(save for a new error I found in the Sound class that I now need to track down).

Your original code for choosing the file was this:

auto openSoundFile()
{
        char[256] filenameBuffer;
        filenameBuffer[0] = 0;
        OPENFILENAME info;
        info.lStructSize = OPENFILENAME.sizeof;
        info.lpstrFilter = "Audio Files\0*.wav;*.ogg\0\0".ptr;
        info.lpstrFile = filenameBuffer.ptr;
        info.nMaxFile = filenameBuffer.length;
        if(GetOpenFileNameA(&info))
        {
                return to!string(filenameBuffer);
        }
        else return to!string("!!failed");
}

However, the original code that Adam Ruppe posted in the D forums didn't return the entire char array. It returned a pointer to it. Correcting that fixes all your problems because a C char* uses \0 as a finalizer, so the to!string function works like it is supposed to. Using to!string on the whole of fileNameBuffer will convert the entire thing, giving you the garbage characters at the end of the good stuff.

Anyways, here's the same code with the revisions I made. http://pastebin.com/nR4WJVx8

A couple of notes about your code:

Color is a struct, so you can skip using "new" when you create Color objects. That way, you don't have to dereference it when you call Window.clear.

When getting a slice, you can actually use "$" as a shorthand for the length of the array.

Hope all that helps!
DSFML - SFML for the D Programming Language.

malkierian

  • Newbie
  • *
  • Posts: 39
    • View Profile
Re: String, Dstring, and Char[] oh my...
« Reply #14 on: December 24, 2013, 05:09:32 pm »
Thanks for the tips, you're right that works perfectly on its own.  But if I try to put it back into my real code for the program, I still get the freezing.  And I still get those debug messages, so apparently I've still got your debug code in there somehow despite rebuilding DSFML and using the latest DSFML-C nightlies.  Perhaps I'm doing that wrong.  When we get that other thread sorted out, I'll try this again.