Juce Array with String


#1

Hi all, I am new to C++, I am coming from a Java background. I am trying to use the Juce Array class and I have my own custom class that consists of a String, and two primitive ints. When I print out the values of the variables, the primitive ints display correctly, but with the String I can only display the address of the String, or if I display it regualarly it just displays some nonense type of characters, it doesn't display the actual contents of the String. If I change the data type from a String to a char, I can then display the actual vallue of the char, a 'C' or a 'D'. But I really need to use a String for me to do what I need to do. Is it not possible to use String with Array?  any help or ideas would be greatly appreciated. Thanks.


#2

You should probably post some code so we can actually see what you're doing. There's not much to go on without the code. Some info, such as how are you printing it, are you using a pointer to the String, etc., would probably be helpful. And just curious, does a std::string do the same thing? 


#3

Header file
/*
  ==============================================================================
    This file was auto-generated!
  ==============================================================================
*/
#ifndef MAINCOMPONENT_H_INCLUDED
#define MAINCOMPONENT_H_INCLUDED
#include "../JuceLibraryCode/JuceHeader.h"
#include <map>
#include <string>
//==============================================================================
/*
    This component lives inside our window, and this is where you should put all
    your controls and content.
*/
class MainContentComponent   : public Component,
                               public ComboBoxListener
{
public:
    //==============================================================================
    MainContentComponent();
    ~MainContentComponent();
    void paint (Graphics&);
    void resized();
    void comboBoxChanged(ComboBox* comboBoxThatHasChanged);
private:
    //==============================================================================
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainContentComponent)
    ScopedPointer<ComboBox> keyComboBox;
    ScopedPointer<TextEditor> messageBox;
};
class MusicalNote
{
public:
    MusicalNote();
    MusicalNote(String noteNameParam, int noteOctaveParam, int noteNumberParam);
    ~MusicalNote();
    String noteName;
    int noteOctave;
    int noteNumber;
    String getNoteName();
    int getNoteOctave();
    int getNoteNumber();
private:
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MusicalNote)
};

#endif  // MAINCOMPONENT_H_INCLUDED

 

------------------------------------------------------------------------------------------------

The CPP file


/*
  ==============================================================================
    This file was auto-generated!
  ==============================================================================
*/
#include "MainComponent.h"
#include <string>       // std::string
#include <iostream>     // std::cout
#include <sstream>  

//==============================================================================
MainContentComponent::MainContentComponent()
{
    addAndMakeVisible(messageBox = new TextEditor());

    addAndMakeVisible(keyComboBox = new ComboBox());
    keyComboBox->addItem("C", 1);
    keyComboBox->addItem("C#/Db", 2);
    keyComboBox->addItem("D", 3);
    keyComboBox->addItem("D#/Eb", 4);
    keyComboBox->addItem("E", 5);
    keyComboBox->addItem("F", 6);
    keyComboBox->addItem("F#/Gb", 7);
    keyComboBox->addItem("G", 8);
    keyComboBox->addItem("G#/Ab", 9);
    keyComboBox->addItem("A", 10);
    keyComboBox->addItem("A#/Bb", 11);
    keyComboBox->addItem("B", 12);
    keyComboBox->addListener(this);

    setSize (600, 400);
}
MainContentComponent::~MainContentComponent()
{
}
void MainContentComponent::paint (Graphics& g)
{
    g.fillAll (Colour (0xff001F36));
    g.setFont (Font (16.0f));
    g.setColour (Colours::white);
    g.drawText ("Hello World!", getLocalBounds(), Justification::centred, true);
}
void MainContentComponent::resized()
{
    // This is called when the MainContentComponent is resized.
    // If you add any child components, this is where you should
    // update their positions.
    keyComboBox->setBounds(20, 20, 100, 25);
    messageBox->setBounds(160, 20,300, 300);
}
void MainContentComponent::comboBoxChanged(ComboBox* comboBoxThatHasChanged)
{
    std::stringstream ss;
    std::stringstream myStream;
    std::stringstream myStream2;
    std::stringstream myStream3;
    //ss << "ComboBox changed: " << comboBoxThatHasChanged;
    //messageBox->setText(ss.str());
    int itemIndex = keyComboBox->getSelectedItemIndex();
    //messageBox->setText(keyComboBox->getItemText(itemIndex));
    

    Array<int> CmajorScaleMapper = {};
    //CmajorScaleMapper.resize(52);
    Array<int> CmajorScale = { 60, 62, 64, 65, 67, 69, 71 };
    int scaleIndex = 4;
    int octaveIndex = 4;
    for (int i = 0; i < 52; i++)
    {
        scaleIndex++;
        CmajorScaleMapper.add(CmajorScale.operator[](scaleIndex) - (octaveIndex * 8));
        if (scaleIndex == 6)
        {
            scaleIndex = 0;
            octaveIndex--;
        }
    }
    int incomingNote = 40;
    int newNote;
    if (incomingNote >= 60)
    {
        int incomingDifference = incomingNote - 60;
        int greaterResult = 27 + incomingDifference;
        newNote = CmajorScaleMapper.operator[](greaterResult);
        //newNote = 60;
    }
    else if (incomingNote < 60)
    {
        int incomingLessDiff = 60 - incomingNote;
        int lessResult = 27 - incomingLessDiff;
        newNote = CmajorScaleMapper.operator[](lessResult);
        //newNote = 50;
    }

    ss << CmajorScaleMapper.operator[](48) << " " << CmajorScaleMapper.operator[](49) << " " << CmajorScaleMapper.operator[](50) << " " << CmajorScaleMapper.operator[](51);
    //messageBox->setText(ss.str());
    ss << "New Note:" << newNote;
    //messageBox->setText(ss.str());
    ////////////////////////////////////////
    std::map<int, int> scaleMap;
    std::map<String, Array<MusicalNote*>> fullKeyboard;
    Array<String> cMajorScale;
    cMajorScale.add("C");
    cMajorScale.add("D");
    cMajorScale.add("E");
    cMajorScale.add("F");
    cMajorScale.add("G");
    cMajorScale.add("A");
    cMajorScale.add("B");
    Array<MusicalNote*> cNotes;
    Array<MusicalNote*> cSharpNotes;
    Array<MusicalNote*> dFlatNotes;
    Array<MusicalNote*> dNotes;
    Array<MusicalNote*> dSharpNotes;
    Array<MusicalNote*> eFlatNotes;
    Array<MusicalNote*> eNotes;
    Array<MusicalNote*> fNotes;
    Array<MusicalNote*> fSharpNotes;
    Array<MusicalNote*> gFlatNotes;
    Array<MusicalNote*> gNotes;
    Array<MusicalNote*> gSharpNotes;
    Array<MusicalNote*> aFlatNotes;
    Array<MusicalNote*> aNotes;
    Array<MusicalNote*> aSharpNotes;
    Array<MusicalNote*> bFlatNotes;
    Array<MusicalNote*> bNotes;
    int octIndex = 3;
    for (int i = 0; i < 7; i++)
    {
        cNotes.add(&MusicalNote("C", i, 60 - (12 * octIndex)));
        cSharpNotes.add(&MusicalNote("C#", i, 61 - (12 * octIndex)));
        dFlatNotes.add(&MusicalNote("Db", i, 61 - (12 * octIndex)));
        dNotes.add(&MusicalNote("D", i, 62 - (12 * octIndex)));
        dSharpNotes.add(&MusicalNote("D#", i, 63 - (12 * octIndex)));
        eFlatNotes.add(&MusicalNote("Eb", i, 63 - (12 * octIndex)));
        eNotes.add(&MusicalNote("E", i, 64 - (12 * octIndex)));
        fNotes.add(&MusicalNote("F", i, 65 - (12 * octIndex)));
        fSharpNotes.add(&MusicalNote("F#", i, 66 - (12 * octIndex)));
        gFlatNotes.add(&MusicalNote("Gb", i, 66 - (12 * octIndex)));
        gNotes.add(&MusicalNote("G", i, 67 - (12 * octIndex)));
        gSharpNotes.add(&MusicalNote("G#", i, 68 - (12 * octIndex)));
        aFlatNotes.add(&MusicalNote("Ab", i, 68 - (12 * octIndex)));
        aNotes.add(&MusicalNote("A", i, 69 - (12 * octIndex)));
        aSharpNotes.add(&MusicalNote("A#", i, 70 - (12 * octIndex)));
        bFlatNotes.add(&MusicalNote("Bb", i, 70 - (12 * octIndex)));
        bNotes.add(&MusicalNote("B", i, 71 - (12 * octIndex)));
        octaveIndex--;
    }
    Array<MusicalNote*> myNotes = cNotes;
    myStream << "Note name: " << myNotes[3]->noteName << "\n";
    myStream << "octave : " << myNotes[3]->noteOctave << "\n";
    myStream << "Note number: " << myNotes[3]->noteNumber << "\n";
    messageBox->setText(myStream.str());

    //messageBox->setText(myStream2.str());
    //messageBox->setText(myStream3.str());

    fullKeyboard["C"] = cNotes;
    fullKeyboard["C#"] = cSharpNotes;
    fullKeyboard["Db"] = dFlatNotes;
    fullKeyboard["D"] = dNotes;
    fullKeyboard["D#"] = dSharpNotes;
    fullKeyboard["Eb"] = eFlatNotes;
    fullKeyboard["E"] = eNotes;
    fullKeyboard["F"] = fNotes;
    fullKeyboard["F#"] = fSharpNotes;
    fullKeyboard["Gb"] = gFlatNotes;
    fullKeyboard["G"] = gNotes;
    fullKeyboard["G#"] = gSharpNotes;
    fullKeyboard["Ab"] = aFlatNotes;
    fullKeyboard["A"] = aNotes;
    fullKeyboard["A#"] = aSharpNotes;
    fullKeyboard["Bb"] = bFlatNotes;
    fullKeyboard["B"] = bNotes;
    Array<int> remappedNotes;
    for (int i = 0; i < cMajorScale.size(); i++)
    {
        Array<MusicalNote*> notes = fullKeyboard[cMajorScale[i]];
        for (int j = 0; j < notes.size(); j++)
        {
            remappedNotes.add(notes[j]->getNoteNumber());
        }
    }
    remappedNotes.sort();
    int inNote = 34;
    for (int i = 0; i < 49; i++)
    {
        scaleMap[inNote] = remappedNotes[i];
        inNote++;
    }
}
MusicalNote::MusicalNote() { };
MusicalNote::~MusicalNote() {};
MusicalNote::MusicalNote(String noteNameParam, int noteOctaveParam, int noteNumberParam)
{
    MusicalNote::noteName = noteNameParam;
    MusicalNote::noteOctave = noteOctaveParam;
    MusicalNote::noteNumber = noteNumberParam;
}
String MusicalNote::getNoteName()
{
    return MusicalNote::noteName;
}
int MusicalNote::getNoteNumber()
{
    return MusicalNote::noteNumber;
}
int MusicalNote::getNoteOctave()
{
    return MusicalNote::noteOctave;
}

 


 

 


#4

Here is a picture of the output.


#5

You are adding adresses of objects on the stack to your array, which right after retrieving it's adresses are going out of scope:

cNotes.add(&MusicalNote("C", i, 60 - (12 * octIndex)));

The MusicalNote("C", i, 60 - (12 * octIndex)) is only valid inside the bracket, right after the add the object is destructed and the memory is freed, if I see this correctly...


#6

That's exactly what I was thinking too. It looks like he's passing the address of a temporary object. He should probably use the new keyword to allocate it on the free store. But then, I don't think the array would delete the objects when it goes out of scope. I believe that's what the OwnedArray is for. Or you could probably use an Array of type unique_ptr<MusicalNote> so the contents are deleted when the Array is deleted. Really though, I don't see why you're storing pointers in the array at all. From what I can tell, you'd be just fine storing normal (non pointer) objects. 

By the way, you don't really have to use the Array class from JUCE, unless you just like it better. I usually just use the Standard Library containers (like std::vector) unless I want something more specialized, such as the OwnedArray. 


#7

Hey, thanks for the help with all of this. I was able to use the OwnedArray successfully. I will look into using the vector as well. Thanks very much for your help and taking the time to answer my questions.


#8

Whenever we get posts like this I always like to recommend reading some C++ textbooks!

It's a difficult language, and well worth investing some time learning the basics. Do that now and it'll save you a lot of pain and confusion later!