full error:
KeyNotFoundException: The given key was not present in the dictionary.
System.Collections.Generic.Dictionary`2[TKey,TValue].get_Item (TKey key) (at <695d1cc93cca45069c528c15c9fdd749>:0)
TonePlayer <lightUp>d__6.MoveNext () (at Assets/TonePlayer.cs:43)
UnityEngine.SetupCoroutine.InvokeMoveNext (System.Collections.IEnumerator enumerator, System.IntPtr returnValueAddress) (at <0ee480759f3d481d82ada245dc74f9fd>:0)
UnityEngine.MonoBehaviour:StartCoroutine(IEnumerator)
TonePlayer:Awake() (at Assets/TonePlayer.cs:14)
when i check the value of the timing array (TonePlayer) and compare it to the value of the timings array (SongManager) their values appear to be the same, but are not recognized as the same value I have tried printing the array's contents and the contents were identical.
both arrays are of the same type (string) and each element is a float converted to a string with 3 decimal places
the .unf file is just a midi converted to json, here are its contents:
{
"header": {
"PPQ": 480,
"timeSignature": [
4,
4
],
"bpm": 120,
"name": "Piano"
},
"tempo": [
{
"absoluteTime": 0,
"seconds": 0,
"bpm": 120
}
],
"timeSignature": [
{
"absoluteTime": 0,
"seconds": 0,
"numerator": 4,
"denominator": 2,
"click": 24,
"notesQ": 8
}
],
"startTime": 0,
"duration": 9.223958333333334,
"tracks": [
{
"startTime": 0,
"duration": 9.223958333333334,
"length": 26,
"notes": [
{
"name": "E5",
"midi": 76,
"time": 0,
"velocity": 0.6299212598425197,
"duration": 0.23645833333333333
},
{
"name": "E5",
"midi": 76,
"time": 0.25,
"velocity": 0.6299212598425197,
"duration": 0.23645833333333333
},
{
"name": "E5",
"midi": 76,
"time": 0.5,
"velocity": 0.6299212598425197,
"duration": 0.23645833333333333
},
{
"name": "C5",
"midi": 72,
"time": 0.75,
"velocity": 0.6299212598425197,
"duration": 0.23645833333333333
},
{
"name": "C5",
"midi": 72,
"time": 1,
"velocity": 0.6299212598425197,
"duration": 0.23645833333333321
},
{
"name": "C5",
"midi": 72,
"time": 1.2499999999999998,
"velocity": 0.6299212598425197,
"duration": 0.47395833333333326
},
{
"name": "C5",
"midi": 72,
"time": 1.9999999999999998,
"velocity": 0.6299212598425197,
"duration": 0.23645833333333344
},
{
"name": "D5",
"midi": 74,
"time": 2.25,
"velocity": 0.6299212598425197,
"duration": 0.23645833333333321
},
{
"name": "F5",
"midi": 77,
"time": 2.5,
"velocity": 0.6299212598425197,
"duration": 0.4739583333333335
},
{
"name": "E5",
"midi": 76,
"time": 3,
"velocity": 0.6299212598425197,
"duration": 0.4739583333333335
},
{
"name": "D5",
"midi": 74,
"time": 3.5,
"velocity": 0.6299212598425197,
"duration": 0.23645833333333321
},
{
"name": "C5",
"midi": 72,
"time": 3.75,
"velocity": 0.6299212598425197,
"duration": 0.23645833333333321
},
{
"name": "E5",
"midi": 76,
"time": 4,
"velocity": 0.6299212598425197,
"duration": 0.23645833333333321
},
{
"name": "E5",
"midi": 76,
"time": 4.25,
"velocity": 0.6299212598425197,
"duration": 0.23645833333333321
},
{
"name": "E5",
"midi": 76,
"time": 4.5,
"velocity": 0.6299212598425197,
"duration": 0.23645833333333321
},
{
"name": "C5",
"midi": 72,
"time": 4.75,
"velocity": 0.6299212598425197,
"duration": 0.23645833333333321
},
{
"name": "C5",
"midi": 72,
"time": 5,
"velocity": 0.6299212598425197,
"duration": 0.23645833333333321
},
{
"name": "C5",
"midi": 72,
"time": 5.25,
"velocity": 0.6299212598425197,
"duration": 0.47395833333333304
},
{
"name": "D5",
"midi": 74,
"time": 6.75,
"velocity": 0.6299212598425197,
"duration": 0.23645833333333321
},
{
"name": "D5",
"midi": 74,
"time": 7,
"velocity": 0.6299212598425197,
"duration": 0.23645833333333321
},
{
"name": "D5",
"midi": 74,
"time": 7.25,
"velocity": 0.6299212598425197,
"duration": 0.23645833333333321
},
{
"name": "D5",
"midi": 74,
"time": 7.5,
"velocity": 0.6299212598425197,
"duration": 0.23645833333333321
},
{
"name": "D5",
"midi": 74,
"time": 7.75,
"velocity": 0.6299212598425197,
"duration": 0.23645833333333321
},
{
"name": "C5",
"midi": 72,
"time": 8,
"velocity": 0.6299212598425197,
"duration": 0.23645833333333321
},
{
"name": "D5",
"midi": 74,
"time": 8.25,
"velocity": 0.6299212598425197,
"duration": 0.4739583333333339
},
{
"name": "E5",
"midi": 76,
"time": 8.75,
"velocity": 0.6299212598425197,
"duration": 0.4739583333333339
}
],
"controlChanges": {
"7": [
{
"number": 7,
"time": 0,
"value": 0.7874015748031497
}
],
"10": [
{
"number": 10,
"time": 0,
"value": 0.5039370078740157
}
],
"91": [
{
"number": 91,
"time": 0,
"value": 0
}
],
"93": [
{
"number": 93,
"time": 0,
"value": 0
}
],
"121": [
{
"number": 121,
"time": 0,
"value": 0
}
]
},
"id": 0,
"name": "Piano",
"instrumentNumber": 0,
"instrument": "acoustic grand piano",
"instrumentFamily": "piano",
"channelNumber": 0,
"isPercussion": false
},
{
"startTime": 0,
"duration": 0,
"length": 0,
"notes": [],
"controlChanges": {},
"id": 1,
"name": "Piano"
}
]
}
output (first loop): timings (SongManager): 0,000, 0,236 timing (TonePlayer): 0,000, 0,236
TonePlayer.cs:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TonePlayer : MonoBehaviour
{
private KeyCode[] keys;
public float minAlpha = 80f;
public float reduceAlphaStep = 1f;
public ToneManager mgr;
public SongManager smgr;
private void Awake()
{
StartCoroutine(lightUp());
keys = new KeyCode[4] { KeyCode.A, KeyCode.S, KeyCode.D, KeyCode.F };
}
IEnumerator lightUp()
{
Dictionary<string[], int> notes = smgr.LoadSong("Assets/test.unf");
Dictionary<int, string> notes_enc = new Dictionary<int, string>();
notes_enc[0] = "C";
notes_enc[1] = "D";
notes_enc[2] = "E";
notes_enc[3] = "F";
for (int i = 0; i < notes.Count; i )
{
string[][] keys=new string[notes.Count][];
keys[0]= new string[notes.Count];
keys[1] = new string[2];
notes.Keys.CopyTo(keys, 0);
string time = keys[i][0];
string duration = keys[i][1];
string[] timing = { time, duration };
mgr.source.PlayOneShot(mgr.tones[notes[timing]]);
print(notes_enc[notes[timing]]);
print(duration);
yield return new WaitForSeconds(float.Parse(duration));
}
yield return null;
}
void Update()
{
for (int i = 0; i < 4; i )
{
if (Input.GetKeyDown(keys[i]))
{
mgr.source.PlayOneShot(mgr.tones[i]);
var temp = mgr.lights[i].color;
temp.a = 1;
//print("set");
mgr.lights[i].color = temp;
}
float alpha = mgr.lights[i].color.a;
if (alpha > (minAlpha / 255f))
{
alpha -= (reduceAlphaStep / 255f);
var temp = mgr.lights[i].color;
temp.a = alpha;
mgr.lights[i].color = temp;
//print(alpha);
}
}
}
}
SongManager.cs:
using System.Collections;
using System.Collections.Generic;
using Newtonsoft.Json.Linq;
using System.IO;
using System;
using UnityEngine;
public class SongManager : MonoBehaviour
{
public string[] first;
private void Awake()
{
LoadSong("Assets/test.unf");
}
public Dictionary<string[], int> LoadSong(string unf_json)
{
Dictionary<string[], int> ret = new Dictionary<string[], int>();
string json = File.ReadAllText(unf_json);
var root = JObject.Parse(json);
var tracks = root.GetValue("tracks")[0]["notes"];
Dictionary<string, int> notes_enc = new Dictionary<string, int>();
notes_enc["C"] = 0;
notes_enc["D"] = 1;
notes_enc["E"] = 2;
notes_enc["F"] = 3;
int z = 0;
foreach (var track in tracks)
{
z ;
float time = ((float)track["time"]);
float duration = ((float)track["duration"]);
string[] timings = { time.ToString("0.000"), duration.ToString("0.000") };
string name = ((string)track["name"])[0].ToString();
//Debug.Log(string.Format("duration: {0}, note: {1}({2})", duration, name, notes_enc[name]));
ret[timings] = notes_enc[name];
}
return ret;
}
}
ToneManager.cs:
using System.Collections;
using System.Collections.Generic;
using System;
using UnityEngine;
public class ToneManager : MonoBehaviour
{
public AudioSource source;
public AudioClip[] tones;
[HideInInspector]
public SpriteRenderer[] lights;
public Transform parent;
public TonePlayer player;
private void Start()
{
lights = GetSpriteRenderers(GetChildren(parent));
/*for (int i = 0; i < 4; i )
{
lights[i].color = SetAlpha(lights[i].color, player.minAlpha);
}
*/
}
public Transform[] GetChildren(Transform parent)
{
List<Transform> children = new List<Transform>();
for (int i = 0; i < parent.childCount; i )
{
children.Add(parent.GetChild(i));
}
return children.ToArray();
}
public SpriteRenderer[] GetSpriteRenderers(Transform[] children)
{
SpriteRenderer[] spriteRenderers = new SpriteRenderer[children.Length];
for (int i = 0; i < children.Length; i )
{
spriteRenderers[i] = children[i].GetComponent<SpriteRenderer>();
}
return spriteRenderers;
}
}
CodePudding user response:
You do
string[] timing = { time, duration };
and then use this a the key in your dictionaries.
This is a new array instance that never existed before and was never added to your dictionaries!
Arrays use Reference Equality, not Value Equality!
In general using arrays as key is often not good for exactly that reason except you really know you are still dealing with exactly the same array reference.
Instead of string[]
you could rather use a Tuple
Tuple<string, string>
or actually why not simply directly
Tuple<float, float>
which provides a proper Value Equality comparison via instead of the default reference equality and therefore would work as key! See also Hashtable with MultiDimensional Key in C#
So your type should rather be a
Dictionary<Tuple<string, string>, int>
CodePudding user response:
The problem is that you are using Dictionary<string[], int>
without custom comparer. Default key comparer for string[]
will look for similar key by comparing the reference and not the string inside, so even their contents are the same they will not matched if they are different array instances.
Because it seems in this case only two strings are needed, so Dictionary<Tuple<string, string>, int>
can be used instead. You can also use Dictionary<string, int>
and use string1 "," string2
or something like that as the key as in this case your strings are not arbitrary string so it is easy to format them as a unique string.
CodePudding user response:
I would recommend you use Dictionary<Tuple<float, float>, int> instead of Dictionary<string[], int> because Dictionary<TKey,TValue> requires an equality implementation to determine whether keys are equal. For string array, it's reference equality by default.
So the following two arrays are not equal:
string[] arr1 = {"1", "2"};
string[] arr2 = { "1", "2" };
Console.WriteLine($"arr1 == arr2: {arr1 == arr2}");
Fix:
var notes = new Dictionary<(float, float), int>();
float time = 1;
float duration = 2;
notes[(time, duration)] = 12;
Console.WriteLine(notes[(time, duration)]);
CodePudding user response:
From what I can see, in your SongManager you are creating Dictionary<string[], int> ret
, but not adding any values to. Instead, you are trying to directly assign values: ret[timings] = notes_enc[name];
. Dictionary is not an array, you should use Add() method, like this: ret.Add(timings, notes_enc[name])
;