This site requires JavaScript, please enable it in your browser!
Greenfoot back
dogzilla
dogzilla wrote ...

2016/4/19

Help using the GreenfootSound class

dogzilla dogzilla

2016/4/19

#
I'm currently working on the textbook exercises 10.45 - 10.50 in Ch 10 of the 2nd edition textbook. It wants me to create a kind of mp3 player thingy. Everything is peachy until I got to the portion where it wants me to change the volume in 10.48. I'm at a complete loss here, am I using the GreenfootSound class incorrectly? I have a reference to the GreenfootSound object in my volumeDown button however, when I attempt to execute the setVolume() method of my GreenfootSound instance called music it only reduces the volume by 4 when its supposed to be 10, then it dosent do anything. I'm feeling pretty dumb here... Source... Code for MyWorld...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)
 
/**
 * Write a description of class MyWorld here.
 *
 * @author (your name)
 * @version (a version number or a date)
 */
public class MyWorld extends World
{
    private VolumeBar volumeBar;
    private GreenfootSound music;
     
    public MyWorld()
    {   
        // Create a new world with 600x400 cells with a cell size of 1x1 pixels.
        super(600, 400, 1);
        prepare();
    }
 
    private void prepare()
    {
        music = new GreenfootSound("Every Planet We Reach Is Dead.mp3");
         
        PlayButton play = new PlayButton(music);
        addObject(play,55,350);
 
        volumeBar = new VolumeBar();
        addObject(volumeBar,545, 210);
         
        VolumeUpButton volumeUp = new VolumeUpButton(volumeBar, music);
        addObject(volumeUp,450,350);
 
        VolumeDownButton volumeDown = new VolumeDownButton(volumeBar, music);
        addObject(volumeDown,350,350);
            
        VolumeBarContainer volumeBarContainer = new VolumeBarContainer();
        addObject(volumeBarContainer,545,210);
    }
}
and code for the button...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)
 
/**
 * Write a description of class VolumeUp here.
 *
 * @author (your name)
 * @version (a version number or a date)
 */
public class VolumeUpButton extends Button
{
    private VolumeBar volumeBar;
    private GreenfootSound music;
    /**
     * Act - do whatever the VolumeUp wants to do. This method is called whenever
     * the 'Act' or 'Run' button gets pressed in the environment.
     */
    public VolumeUpButton(VolumeBar volumeBar, GreenfootSound music)
    {
        this.volumeBar = volumeBar;
        this.music = music;
    }
 
    public void act()
    {
        //For testing purposes...
        //System.out.print(music.getVolume() + "\n");
        onClick();
    }  
 
    public void onClick()
    {
        if(Greenfoot.mouseClicked(this) && volumeBar.getImage().getHeight() < 360)
        {
            //For testing purposes...
            //System.out.print(music.getVolume() + "\n");
            volumeBar.getImage().scale(volumeBar.getImage().getWidth(),volumeBar.getImage().getHeight() + 36);
            volumeBar.setLocation(volumeBar.getX(), volumeBar.getY() - 18);
            music.setVolume(music.getVolume()+10);
        }
    }
}
Im at a loss here, when I send getVolume to output it gives me some funky stuff... any help would be greatly appreciated, Thanks.
danpost danpost

2016/4/19

#
What is the output when you uncomment lines 34 and 35 and click on the button a few times?
dogzilla dogzilla

2016/4/19

#
I figured it out, was up until 5am rooting this one out. I am currently in class right now but when I get home I will post an in-depth response on what is happening. It appears to be an issue with Greenfoot itself. Somehow the setVolume() function when passed a parameter, before that value actually gets set to the volume it goes through a logarithmic function. So when I call setVolume(2), getVolume() returns 15, when I call setVolume(10), getVolume() returns 50. Like I said I got it to work with a work around, will post after class. Any thoughts? Is this a known issue?
dogzilla dogzilla

2016/4/20

#
So, bottom line up front. If you want to adjust the volume of a GreenfootSound instance you cannot do something like this:
1
2
setVolume(getVolume()-10)
//This will produce undesired results
I’ll explain why later, just know now that you have to do something like:
1
2
setVolume(10)
//Do this instead
Or, if you want to have an incremental in there you could do something like:
1
2
3
4
int volume = 50;
volume += 10;
setVolume(volume)
//Or this
Now, the reason you cannot call the getVolume() method and then increment that value takes some explaining. So if you’re having a similar issue and you just showed up to find out the answer to your issue, there ya’ go. Now if you want to know why this won’t work (which if you are on the Greenfoot site to learn programming you probably should), pull up a chair, take your shoes off, kick your feet up, and hold my hand as we jump down this rabbit hole. I was working on the textbook exercises 10.45 - 10.50 in Ch 10 of the 2nd edition Greenfoot textbook. It has you creating a program that plays an mp3 player. It requires you to make some buttons and an interface providing functionality to play, pause, change the volume, and have an on screen representation of the volume level. Sounded easy enough. I thought about the problem, came up with a solution and started to implement. But I ran into a problem. Code for world…
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)
/**
 * Write a description of class MyWorld here.
 *
 * @author (your name)
 * @version (a version number or a date)
 */
public class MyWorld extends World
{
    private VolumeBar volumeBar;
    private GreenfootSound music;
      
    public MyWorld()
    {   
        // Create a new world with 600x400 cells with a cell size of 1x1 pixels.
        super(600, 400, 1);
        prepare();
    }
  
    private void prepare()
    {
        music = new GreenfootSound("Every Planet We Reach Is Dead.mp3");
          
        PlayButton play = new PlayButton(music);
        addObject(play,55,350);
  
        volumeBar = new VolumeBar();
        addObject(volumeBar,545, 210);
          
        VolumeUpButton volumeUp = new VolumeUpButton(volumeBar, music);
        addObject(volumeUp,450,350);
  
        VolumeDownButton volumeDown = new VolumeDownButton(volumeBar, music);
        addObject(volumeDown,350,350);
             
        VolumeBarContainer volumeBarContainer = new VolumeBarContainer();
        addObject(volumeBarContainer,545,210);
    }
}
Code for button…
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
//VolumeDown class is similar just decrements the volume by 10
import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)
  
/**
 * Write a description of class VolumeUp here.
 *
 * @author (your name)
 * @version (a version number or a date)
 */
public class VolumeUpButton extends Button
{
    private VolumeBar volumeBar;
    private GreenfootSound music;
    /**
     * Act - do whatever the VolumeUp wants to do. This method is called whenever
     * the 'Act' or 'Run' button gets pressed in the environment.
     */
    public VolumeUpButton(VolumeBar volumeBar, GreenfootSound music)
    {
        this.volumeBar = volumeBar;
        this.music = music;
    }
  
    public void act()
    {
        //For testing purposes...
        //System.out.print(music.getVolume() + "\n");
        onClick();
    }  
  
    public void onClick()
    {
        if(Greenfoot.mouseClicked(this) && volumeBar.getImage().getHeight() < 360)
        {
            //For testing purposes...
            //System.out.print(music.getVolume() + "\n");
            volumeBar.getImage().scale(volumeBar.getImage().getWidth(),volumeBar.getImage().getHeight() + 36);
            volumeBar.setLocation(volumeBar.getX(), volumeBar.getY() - 18);
            music.setVolume(music.getVolume()+10);
        }
    }
}
This code was producing some unexpected results. The volume is originally set to 100. So when I clicked the volume down button you should expect the getVolume() method to return 90, however this post wouldn’t exist if it did, it only decreased by three to 97. I checked the code, Its coded in there to decrease by ten, so I clicked it again. This time it only decreased by one to 96, bizarre! I prayed to the machine spirit this time hoping to get in his good graces. I clicked it again, this time no change to the volume... Now I want to talk a little bit about my adventure identifying the problem. Machine spirit wasn’t pleased. Profanities ensued. I spent quite a long time trying to figure it out, seemed to be making no head way. So I added this to run once and output what the value does as you call the setVolume() method:
1
2
3
4
5
for(int index = 0; index <= 100; index++)
{
    music.setVolume(index);
    System.out.print(index + " " + music.getVolume() + "\n");
}
This steps through every possible parameter that could be sent to the setVolume() method and outputs it to the console. This is what it pooped out: set get set get set get set get 1 0 26 70 51 85 76 94 2 15 27 71 52 85 77 94 3 23 28 72 53 86 78 94 4 30 29 73 54 86 79 94 5 34 30 73 55 87 80 95 6 38 31 74 56 87 81 95 7 42 32 75 57 87 82 95 8 45 33 75 58 88 83 95 9 47 34 76 59 88 84 96 10 50 35 77 60 88 85 96 11 52 36 77 61 89 86 96 12 53 37 78 62 89 87 96 13 55 38 78 63 89 88 97 14 57 39 79 64 90 89 97 15 58 40 80 65 90 90 97 16 60 41 80 66 90 91 97 17 61 42 81 67 91 92 98 18 62 43 81 68 91 93 98 19 63 44 82 69 91 94 98 20 65 45 82 70 92 95 98 21 66 46 83 71 92 96 99 22 67 47 83 72 92 97 99 23 68 48 84 73 93 98 99 24 69 49 84 74 93 99 99 25 69 50 84 75 93 100 100 Infuriating, this seems to make no sense. When I call setVolume(50), getVolume() returns 84? What is going on here? I scour my code to find where this could be happening but turn up nothing. Discouraged and delirious (its about 3am at this point) I ask my roommate to take a look. He suggests graphing the output and see if it makes any sense. Which I do and… [Disallowed URL] Bingo! Its logarithmic. So what was happening with my original code: setVolume(getVolume()-10) First we click the volumeDown button. Then we call setVolume(getVolume()-10). Inside the setVolume() method we call getVolume() which returns 100 then we decrease that by 10 for a total of 90. So setVolume(90) sets the volume to… Refer to table above… 97. Then if we click again we call setVolume(getVolume()-10). Inside the setVolume() method we call getVolume() which returns 97 then we decrease that by 10 for a total of 87. So setVolume(87) sets the volume to… Refer to table above… 96. Then finally, if we click again we call setVolume(getVolume()-10). Inside the setVolume() method we call getVolume() which returns 96 then we decrease that by 10 for a total of 86. So setVolume(86) sets the volume to… Refer to table above… 96. Ahhhhhhhhh… We get stuck. Definitely not the results we desired. Somewhere in between setVolume() and getVolume() there is a logarithmic function. Not sure the exact function but it is something like: (0.993413) * Math.pow(1.04776, parameter) where 0 <= parameter <= 100 My math is a little rusty but that formula produces the table above. So I guess if you want to use the getVolume() method in the setVolume() method you could do something like:
1
setVolume( ((0.993413) * Math.pow(1.04776, getVolume())) -10)
Not sure why you would want to do that but there it is, anyway I digressed. So in order for the setVolume() method to function in the way I want I had to get a little creative:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)
 
/**
 * Write a description of class MusicController here.
 *
 * @author (your name)
 * @version (a version number or a date)
 */
public class MusicController extends Actor
{
    ////Variable declarations////
    /**I am using an array to step through the volume levels
     *since the normal setVolume() method is logarithmic, and
     *dosent produce the desired results
     */
    private int[] logArray = new int[11];
    private int index = 10;
 
    //Holds a reference to the song we want to play
    private GreenfootSound music = new GreenfootSound("Every Planet We Reach Is Dead.mp3");
 
    ////Constructor////
    //Default constructor with no parameters
    public MusicController()
    {
 
    }
 
    ////Getters////
    //Returns the value in the volumeLogArray
    public int getArrayAtCurrentIndex()
    {
        return logArray[index];
    }
 
    //Returns the index of the volumeLogArray
    public int getIndex()
    {
        return index;
    }
 
    //Returns a reference to the GreenfootSound music
    public GreenfootSound getMusic()
    {
        return music;
    }
     
    ////Effectors////
    //This initializes the array to the hold the desired volume
    //levels since setVolume is logarithmic
    public int[] volumeToLogArray()
    {
        logArray[0] = 1;    //The volume level becomes: 0
        logArray[1] = 2;    //The volume level becomes: 15
        logArray[2] = 3;    //The volume level becomes: 23
        logArray[3] = 4;    //The volume level becomes: 30
        logArray[4] = 7;    //The volume level becomes: 42
        logArray[5] = 10;   //The volume level becomes: 50
        logArray[6] = 16;   //The volume level becomes: 60
        logArray[7] = 26;   //The volume level becomes: 70
        logArray[8] = 40;   //The volume level becomes: 80
        logArray[9] = 66;   //The volume level becomes: 90
        logArray[10] = 100; //The volume level becomes: 100
 
        return logArray;
    }
 
    //Decreases the volume by decreasing the index 
    //of the volumeToLogArray
    public void volumeDown()
    {
        index--;
        music.setVolume(getArrayAtCurrentIndex());
    }
 
    //Increases the volume by increasing the index 
    //of the volumeToLogArray
    public void volumeUp()
    {
        index++;
        music.setVolume(getArrayAtCurrentIndex());
    }
 
    //For future use.......
    public void nextTrack()
    {
 
    }
}
So here I created a class called music controller that will handle all the music stuff that the program is going to do. In it we create an array and initialize it to the values that would produce the desired result. Here I wanted to change the volume by increments of ten, however since the logarithm kinda messes that up and we can’t send a double to the setVolume() method, the values are a little off but no big deal. (i.e. we get 42 instead of 40 and 23 instead of 20). Throw in some methods to change the index of the array and boom, It works... This post is super long but I figured if I can save someone else the headaches and heartaches that I went through to get to this point, it would be worth it. If I am over thinking this or not using the methods as intended please, by all means let me know. Stay sane everybody.
danpost danpost

2016/4/20

#
I think this may be a bug in greenfoot. One would think that the 'get' method would return the same value used in the 'set' method.
dogzilla dogzilla

2016/4/20

#
That is what I expected too, simple and intuitive. The way it stands now its neither simple nor intuitive. Is there a reason to have the volume logarithmic? I'm not sure why they would code it like and want to understand. Also @danpost are you a moderator on here? Seems like every discussion on here is answered by you haha. If so you should know where I can find the the site/forum/posting rules, couldn't find them anywhere.
danpost danpost

2016/4/20

#
dogzilla wrote...
That is what I expected too, simple and intuitive. The way it stands now its neither simple nor intuitive. Is there a reason to have the volume logarithmic? I'm not sure why they would code it like and want to understand. Also @danpost are you a moderator on here? Seems like every discussion on here is answered by you haha. If so you should know where I can find the the site/forum/posting rules, couldn't find them anywhere.
No -- I am not a moderator here; just an experienced member who likes to help out. There are links below the reply box you could check out. I could not find anything specific to rules for posting in general; however, the main thing is keeping it respectable and maintaining the basic goals of the site while not trashing the site.
You need to login to post a reply.