2014-09-15 05:56:29

Hi all,
I want to do something a little different with the Memory Train example. I have working menu music, but I figured I'd try to spice it up.
I've got 30 music tracks for this version of it. The idea is that my menumusic track will play at the main menu, and when a user starts the game, the initial idea is to have memory train be memory train, but have a selection chosen randomly from these thirty tracks which, when I can figure it out, I'll make a sounds folder and make a music directory in that folder, wherein the files will be named music1.ogg, etc all the way up to 30.
In the example, the left and right brackets for the tone sounds correspond to sound handles right? So Tone is just a variable handle pointing to four sound files of four tones each.
So instead of making a simple global variable of music, I decided to make a handle for music which would point to the thirty tracks, but once I looked at the "load" code for the tone sounds and then translated what I had to do for that particular method for the music variable, I was like OMG, I gotta make an Array for this.
I'll look at arrays in the language Tutorial again, but how best would the Random function in BGT be used in this case?
Thanks.

2014-09-15 09:12:36

The variable tone is actually an array of sounds and the left and right brackets after sound mean an array of sounds. THe @  sign is what tells you that you are looking at a handle. So sound[] (note the punctuation) is not, as you seem to think, an array of sound handles. This is actually really important because if you remember, a handle must point back to an object. In short, a handle is just a way to make things easier for you, because if you are developing a game, you don't ever have to use handles, but using them makes your task tremendously easier and your code cleaner.
Following from the handles vs arrays thing, you talk about music as being a handle. You seem to be sort of confused as to what a handle is and what an array is. The tones are an array of sounds, and nothing else, so handles have nothing to do with it right now. The way the tutorial shows you how to load sounds gets really cumbersome if you are loading more than about 4 sounds, because you have to load each file separately. For arrays with more items, you will want to do something similar to what the language tutorial shows you, and use a loop to automatically increment your array index to load more files automatically.
Here's a sample code fragment that I haven't tested. That usually means you'll see some minor compile errors, but the gist of how you ought to work it is there. I'll try and explain things with comments to help you.

sound[] music(30);//declare an array of sounds called music and give it a size of 30.
void main()
{
show_game_window("stuff"); //allows keyboard input
//use a loop to expedite loading of sequentially numbered files
for(uint x=1; x==music.length(); x++) //what will happen now is that the variable x, which we declared in the for statement, will have 1 added to it each time the loop runs. It will stop when x = the length of the music array, which we defined to be 30.
{
music[x-1].load("sounds/music/"+x+".wav"); //array index always starts at 0 and goes to length()-1. Since x starts at 1 and goes to music.length(), you have to do a minus 1 in order to keep the array index and the variable of x synchronized. Notice also how I used string concatonation in the call to sound.load, in order to quickly load the files with that number. I assume that the file extension is wav, for the sake of simplicity.
}
//play a random music sound and wait for 5 seconds so that you can hear part of it.
music[random(0,music.length()-1].play(); //look carefully at the arguments I give to the random function. Remember that the minimum index of any array is 0 and the maximum index is the array's length minus 1. So the generator will now return a number between 0 and 29, and the sound associated with that file will play, if it loaded correctly.
wait(5000);//wait for 5 s.
}

I like to sleep, Sleep is good,
This is how I do it: Lie on a nice warm cozy bed, and dream dreams about how to rule the world!
Follow @TheGreatAthlon5 on twitter for humorous facts and game updates!
If you like my posts, thumb me up!

2014-09-15 15:38:30

Thanks for this. Yeah, in my head I wasn't confused, I guess I just wrote that because I was trying to explain what I wanted and, based on what I'm learning, tried to go about it in a weird way because the tutorial doesn't show it the same way. Anyhow, I already have an array with size 30, so I'll create my loop later. Knowing this I may even add more tones for harder difficulties later on.

2014-09-16 03:26:54

Hmm, so I tested this separately. The array is created and loads a random sound properly it seems, but I can't get the compiler to work out that after it's loaded, it should play it. The compiler keeps throwing that it expected a right parren or comma instead of left or right brackets in this line:
music[random(0,music.length()-1].play();
I guess it's getting confused with the call and expects more parameters. Either that, or it's not loading and isn't throwing an error and there isn't a sound loaded so the compiler is throwing an error because it can't find anything...

2014-09-16 05:03:05

Your missing a ).

original line:
music[random(0,music.length()-1].play();

You open the random function, give the 2 parameters between 0 and music.length()-1, but you don't actually close the random function. the fixed line would be:

music[random(0,music.length()-1)].play();

Deep in the human unconscious is a pervasive need for a logical universe that makes sense. But the real universe is always one step beyond logic.

2014-09-16 19:30:24

Huh. It works now but kinda doesn't work. What I mean is that my window opens for five seconds, but nothing actually plays. Could this be because the sound isn't loading? My main menu music loads just fine, so not sure what's up. Some of these songs are over six minutes, could length have anything to do with it? Maybe if I stream them it'll play?

2014-09-16 19:49:03

I doubt it.  6 minutes of audio is a bit extensive, however, and probably should be streamed.  nevertheless, the memory usage is bounded below by 2*sr*length_in_seconds and above by 4*sr*length_in_seconds, so we have: 31752000 to 63504000 per song, assuming that it's at 44.1 khz (most things are) and BGT uses 4-byte samples.  Loading all 30 puts you barely under 2 GB, but I'd expect that BGT would warn you in some way (most languages outright crash at this point).
I have never seen a system that asynchronously loads sounds and "hopes" that they're ready in time.  If you're getting to the sleep, then the sounds are probably loaded; as I've noted, you're pushing but not quite breaking the RAM limits.  This is a case of okay-but-not, by which I mean that the RAM probably isn't your issue in this toy example but will be as soon as you go further.  If BGT is using 16-bit samples, then you're okay.  But we can't really know that.  Task manager can show you RAM usage, however, and switching to streaming is probably only a couple lines at this point.

My Blog
Twitter: @ajhicks1992

2014-09-17 00:14:33

Yeah, this picks a random song in an array, loads it and plays it for five seconds. Once this works, I'll implement it into my game function and loop it. The thing is, it's not like it's freezing or anything. and would there be an error when loading it or should I create some error check functions?

2014-09-17 04:14:20

I don't know what kind of error will happen.  On account that BGT does not to my knowledge have exception handling (another nail in the coffin, as far as I'm concerned), errors you don't handle will probably silently do nothing.
In all the languages I've worked with save C, unhandled errors loudly crash the program and print the "stack trace", a record of the line that caused the error and how we got there.  You don't have this, so the only way to know about errors that are your fault as the programmer is to always check everywhere lest the problem show up 50 lines later because you don't have exceptions.  Needless to say, welcome to the land of if statements all day long.  Given that load and play both return a boolean indicating success, rather than doing something more sensible (and I can think of two better options), it's quite possible that adding error checks will tell you what is failing.  But as far as I can see, these functions do not also tell you why.  My advice is to make and keep logs, but that's probably more advanced than you want to go at the moment.  Because BGT does not associate itself with a console window, you don't have anywhere easily viewable to send them.

My Blog
Twitter: @ajhicks1992

2014-09-17 12:52:05

My advice to you is to, in your void main function, use the set_error_output function before you do anything. When your program closes, open the error file you told bgt to create and it will give you all the engine errors that it had during the last runtime. This includes things like file not found, which most likely is the problem if you entered the path badly. It could also be something else I'm not thinking of. If you see file not found you'll probably want to start debugging your sound loading code to see what they're exactly loading. Having 30 music files will take a noticeable amount of time to load though. Just keep that in mind. If the program loads too fast, at least some of the files probably didn't load right.

I like to sleep, Sleep is good,
This is how I do it: Lie on a nice warm cozy bed, and dream dreams about how to rule the world!
Follow @TheGreatAthlon5 on twitter for humorous facts and game updates!
If you like my posts, thumb me up!

2014-09-17 14:32:04

@Orin: I would guess that a 5 minute song might have trouble loading on some machines, but it depends entirely on the amount of ram that you have. Try to stream them, and if that works we can look into what is actually happening when you try to load the sounds. Once you can verify that streaming works, I will look further into it and get back to you. If streaming does not work either, the best way to proceed would be for you to send me some of the files that don't work and I will investigate further.

@camlorn: Quick correction. While you have no try/catch blocks in BGT, there are certainly runtime exceptions that pop up. This happens both in situations such as when you try to access an array element that is out of bounds, when you divide by 0, and when the C++ runtime throws an exception (std::exception to be exact). Those exceptions are translated into a BGT runtime error and displayed immediately to the user with the line number, function, etc. They are not silently ignored, as you are assuming. In addition, as has been previously mentioned you have the set_error_output function which is used to try to avoid the case you describe with endless if statements.

And now on a related, but more general note. You are of course more than welcome to criticise BGT as much as you want, I have absolutely no problem with that. But if you do, you should at least be informed as to what the facts are. Misinformation is a very different beast from researched, factually correct criticism. Saying things such as that BGT hides 20 years of programming knowledge and methodology, while certainly false, is not harmful as it is clearly your own personal view. BGT is a language like any other, and any type of methodology or coding guidelines etc can be followed just like they can in C++. Certainly you don't have the same amount of literary material available to you, but this is hardly the same as claiming that BGT hides this information from you. In any case, while I feel that these types of claims are entirely unfounded, they are clearly your own personal views and so I have no real problem with them. But when you start making claims that are based on a clear lack of knowledge, I feel I should bring attention to that. I respect your work and your opinions, but please look up the facts before you start assuming things and then making claims based on those unverified assumptions.

Thank you!

Kind regards,

Philip Bennefall

2014-09-17 15:26:57

I went to the help file.  I checked the return value on both functions. I tried both the index for error and errors and the search for both error and errors.  I'm not sure what else you want me to do for fact checking.  Read the entire help file from top to bottom?  it's not my fault if the .chm doesn't list key concepts in either place.  But I did do fact checking; I didn't just pull this out of my hat.  If the help file is organized such that the obvious methods for finding the information I'm looking for don't work, that's not on me.

My Blog
Twitter: @ajhicks1992

2014-09-17 16:11:05

@camlorn: If you look under references/foundation layer/function reference/debugging and analysis/set_error_output, for instance, you would find one solution to avoid the endless if checks situation you are describing. Similarly, you will find several mentions of runtime errors in the help file that describe potential situations when they can occur. I obviously do not expect you to read the entire help file, but I do assume that people who are going to criticise someone else's work do so in a respectful and factually correct manner. Statements like "another nail in the coffin " are really not constructive. I don't understand where all this hostility stems from in the first place. BGT is now a free piece of software that I make available and maintain in my free time, and I don't see why you feel the need to repeatedly take jabs at it for one reason or another. If you have a problem with the work I do or the way in which I present the software, why not simply drop me a line and say so? I am definitely open to a constructive discussion on shortcomings in the software that I can address (especially from other developers), but if you don't give me that opportunity there's really not much I can do.

In my personal view, given the size of the community, it is far better if developers actually try to help one another. For example, I could go through and read the manual for Libaudioverse and then pick out every little piece that I dislike, disagree with or find faulty, and present that in a very negative light. But why should I? It doesn't encourage you as a developer to make it better, it doesn't help your end users and it doesn't achieve anything constructive whatsoever. TO be clear I am not saying that I dislike Libaudioverse, it looks cool. I am merely using it as an example. My point is, why rip apart someone else's work in such a fashion? In the mainstream community such things would probably get lost in the noise, but in a community which is as small as ours it is really quite harmful for the people involved.

Kind regards,

Philip Bennefall

2014-09-17 22:37:57

I will drop you a line.  Before calling me out for being generally negative about BGT and complaining that I'm not helping, take your own advice; you didn't need to highjack the thread and could have likewise dropped me a line privately.  Unless I'm mistaken, my e-mail is public on these forums.  I would have gladly gone into this with you; I and many people that I know who are blind developers all agree with my criticism, which I believe I have stated elsewhere.  A simple "actually, you're wrong and here's how" would have been sufficient, I think. 
I do not care if people point out problems with Libaudioverse, either.  Please, feel free to pick it apart as much as you want.  Especially now, while it's in pre-pre-alpha.  That will just make it better software when it's ready.  It is to my advantage to not only let you but also to encourage you to do so.  I'm not going to say that any publicity is good publicity, but any publicity that generates discussions of shortcomings helps make those shortcomings go away.  Also, libaudioverse is only tangentially for others; it's the software I want for my projects, and the fact that others can and will want to use it is not the primary reason I am writing it.
My fact checking should have been sufficient.  The index and search should have turned this up.  Proving the existence of something is easy; proving the nonexistence of something is hard.
Unless I am really, really missing something, my point still stands.  Examples can silently fail.  I am aware of few programming languages where this is the case, at least if you're using halfway decent libraries.  Providing a logging framework does not solve the problem, especially if it's not on by default (the documentation does not say that it is).

My Blog
Twitter: @ajhicks1992

2014-09-17 23:08:29

Hello,
I hardly think that saying the thread was highjacked is a fair statement.
If someone were to give non-constructive criticism to me in a thread that concerns my product, I would definitely step in and contribute the discussion.
But that is beside the point. I do not understand your statement about bgt errors.
They are there, trust me! Many an hour as been spent resolving that pesky runtime error which you say is non-existant. Unless, of course, you are referring to something else?
Are you saying that the game should die if a sound fails to load? That's reasonable for the game programmer to implement, but not for the engine itself. You may wish to give a custom error if a sound fails to load. I catch errors such as this in my games and would find BGT to be less flexible if you didn't have that option.
So, if neither of these errors are what you are referring to, please let me know. I'm always interested in new programming concepts!
Thanks,
Aaron

2014-09-17 23:44:52

@camlorn: I definitely did not highjack the thread. I started by responding to the original question, offering some advice as well as to look into the issue if there is indeed a problem with the engine here.

As for following my own logic, my message to you was in response to the misinformation, which was public. So I responded in the same fashion. I have been seeing these types of remarks of yours for quite some time, and while I feel that many of them are unfair such as the claim that BGT hides years of programming methodology and knowledge from its users, I ignored them because I felt it was unnecessary to start a discussion since they were personal opinions of yours. The difference I see here is that this is incorrect information to which I wanted to bring attention, and at the same time point out that it's more than a little unnecessary to continuously pick apart someone else's work in such a fashion. When I say pick apart, I mean that in the negative sense. Your comments, as far as I understood them, were not intended to help improve the software. "Another nail in the coffin" in the given context hardly adds anything constructive for the developer whether it be aimed at BGT, Libaudioverse or any other piece of software. It is not a nice way of approaching it, in my view.

I completely agree with you that most discussions of shortcomings are good, but only as long as they are constructive or helpful in some way. If yours were meant that way and I misread them, I would gladly apologize.

To address the issue of engine errors, since we don't have try/catch blocks I figured that the most reasonable way to indicate errors was to return bool in most cases and then have get_last_error/get_last_error_text and friends. I would say that it is generally bad not to check for documented failure conditions - far from all frameworks make use of exceptions even if the language supports them. I usually do this in trivial wrapper functions myself. The logging framework is not meant to solve the problem, merely to provide some hints to the developer if they get stuck on something.

Finally, regarding the help file. I definitely agree that the searching needs to be improved, but I would say that browsing the contents for a few minutes would not be an unreasonable expectation while you are trying to find information. As I showed in my last message, there is an easy to find section in the help file called "Debugging and Analysis" which explains a lot of the error reporting concepts used in BGT. Whether you consider these methods valid or not is a different discussion.

Kind regards,

Philip Bennefall

2014-09-18 05:55:27 (edited by Orin 2014-09-18 06:22:55)

Hi all,
Thanks to the set_error_output function, I think I've found out what is wrong with my main script. The music array is a different issue entirely.
This is what happens with the music array.
Engine error from function: bool sound::play() const

Error: No valid resource associated.

Call stack size: 1

File: C:\BGTStuff\Memory Train Deluxe\MusicArrayTest.bgt
Line: 15 (1)
Function: void main()




So something is up with the play function.
Since from the users perspective my main script is okay with my main menu music playing, I decided to add set_error_output to it to see if there was any hidden, internal problems with it. The log revealed that the compiler can't find the files for my tones, Despite them being in "sounds/1.wav", etc, which is what I have in my code. Despite this, it still says File not Found for each of them. Yet it found my Main Menu music, "sounds/music/menu.ogg".
Is it because I didn't start the path with a slash, like
"/sounds/1.wav"?

Glad I got to this before I made a game function, otherwise nothing would play because all this time I thought the sounds were loading. It may explain the music example too in that all that's really happening is a window popping up for five seconds and it's not loading jack.
I'm just puzzled at why it can find and load the main menu music but it can't find the sounds I put in /sounds. It found that file in /sounds/music. If it can find a file in the subdirectory...
Anyone have any ideas on this?
Edit: Checking the lines of the error log generated for my main script, each "File not Found" is for each tone. 1-4, and the error sound. It of course skips the menu one, as it found that.

2014-09-18 08:41:11

If you are using the code example I put in post 2, you'd want to have the music files as sounds/music/1.wav, sounds/music/2.wav, sounds/music/3.wav etc. And remmember that everything is case sensitive, so make sure all the folder names are lower case. Without an actual look at your folder structure, I can't really say what's wrong though

I like to sleep, Sleep is good,
This is how I do it: Lie on a nice warm cozy bed, and dream dreams about how to rule the world!
Follow @TheGreatAthlon5 on twitter for humorous facts and game updates!
If you like my posts, thumb me up!

2014-09-18 13:22:10

@Orin: If it is a matter of specifying the wrong path to the files somehow, I would try printing out the same string that you pass to the load or stream method for the given sound. Then you can see what is actually being passed there. If you don't manage to get it working, feel free to send me a zip with your script and your sounds and i'll have a look when I get a chance.

Kind regards,

Philip Bennefall

2014-09-18 15:36:03 (edited by Orin 2014-09-18 16:10:15)

Hmm. How do I use the print function to do that? As far as I'm aware, I pass the path to the sound to it, which apparently to the compiler is wrong. I'll probably just put the script on DropBox or SS so that everyone can take a look at it.
I switched my uppercase S in sounds and made it lowercase, however this didn't seem to change anything. It's lowercase in the code.

Edit: Here's the script. The large file size is due to the music. When I release it I'll give credit where it's due as it's required by the licence, but for now:

https://www.sendspace.com/file/2a0rfg

2014-09-18 16:34:32

@Orin: I've looked at your package and I notice a few things. First, your Wave files in the sounds directory are called 1.wav.wav, 2.wav.wav, etc. You probably haven't configured Windows to display known file extensions.

In terms of the code, Memory Train Deluxe.bgt runs as expected given that all it is meant to do is display a menu and play a music track. That worked fine for me. However, MusicArrayTest.bgt has a problem. Have a look at the following lines:

for(uint x=1; x==music.length(); x++) //Creates a for loop that will pick from the music array of size 30.

{
music[x-1].load("sounds/music/"+x+".ogg"); //Loads a random sound from the Array.
}

This means that the loop will never run, because i doesn't start out as being the length of the array. The lines should read:

for(uint x=1; x<=music.length(); x++) //Creates a for loop that will pick from the music array of size 30.

{
music[x-1].load("sounds/music/"+(x-1)+".ogg"); //Loads a random sound from the Array.
}

However, given the size of the files when decoded to PCM they will not load on most machines. So the line inside the loop should be changed to:

music[x-1].stream("sounds/music/"+(x-1)+".ogg"); //Loads a random sound from the Array.

With these changes made, the program works just fine on my machine.

Good luck!

Kind regards,

Philip Bennefall

2014-09-18 20:12:47 (edited by Orin 2014-09-18 20:14:23)

Hi Philip,
Thanks for the help, it works like a charm... kind of.
I changed the array to stream and it's working, however I opened the program and it played a track for five seconds as intended, but it generated an error log saying that the file couldn't be found? Huh? It just played it. So is my four tone sounds loading in the main script or not? I can't tell, because set_error_output generated what I assume to be a false error since the file played as intended.

2014-09-18 23:04:33

@Orin: It might be refering to the files you are loading that have the extension .wav.wav. They won't load as you expect because you may not see the actual extension in Windows explorer. The engine would not give that error unless it failed somewhere. It should tell you the line on which it failed in the callstack, which will tell you more. Feel free to paste the callstack here as well as your updated code and I can be more specific.

Kind regards,

Philip Bennefall

2014-09-19 00:33:44

Hi Philip,
I changed the extensions back, turned off the hide known extensions setting in Windows, and I don't get that error anymore.
I did, however, make the Memory Train game and I get this single error on line 162.

The error is 'Unexpected token "While", when there's a while loop a few lines up that looks the same and it doesn't complain about that one. While I'd prefer not to copy and paste from the tutorial and instead usually type it, toward the end I started to copy and paste, changing the documentation variables to my new ones.
This was a pasted result, and I was able to correct the extra brace somewhere, but now only this single error, "Unexpected Token While" comes up for this single line:
while(tone[current].playing)
Should there be two left parrens at the beginning of "tone"? I can't recall and don't want to make anymore unexplainable errors.

2014-09-19 01:24:08

@Orin: There is nothing wrong with that line in and of itself, so there must be something to do with the scope. My guess is that it is related to a brase appearing somewhere above that line, where it shouldn't be. I can't really say much more though without seeing your code in its entirety again.

Kind regards,

Philip Bennefall