Making a timer in Unity that instantiates an object at x time.

So I’m working on a rhythm game, its a space shooter and the enemies spawn in tune with the song that is playing(it’s all hard coded in) right now I’m using coroutines and waitforsecond commands but for some reason I find that they turn out to be not completely accurate and go out of beat down the line. So I was thinking of maybe creating a timer and when the timer hits say 1.5 seconds it will spawn an enemy then at 3 seconds spawn another one etc, etc, but I’m not sure how to do that. I’ve tried using a couple different ideas but none have worked, I’m not even sure if I can use it this way. Any ideas?

Also here’s what my code looks like as of now(it’s super repetitive):

    IEnumerator SpawnTimer(){
        //part1(0)
        yield return new WaitForSeconds (0);
        Instantiate (enemies[Random.Range(0, enemies.Length)], Spawn2.transform.position, Spawn2.transform.rotation);
        yield return new WaitForSeconds (1.5f);
        Instantiate (enemies[Random.Range(0, enemies.Length)], Spawn14.transform.position, Spawn14.transform.rotation);
        yield return new WaitForSeconds(1.5f);
        Instantiate (enemies[Random.Range(0, enemies.Length)], Spawn4.transform.position, Spawn4.transform.rotation);
        yield return new WaitForSeconds(1.5f);
        Instantiate (enemies[Random.Range(0, enemies.Length)], Spawn12.transform.position, Spawn12.transform.rotation);
        yield return new WaitForSeconds(1.5f);
        //part2(6)
        Instantiate (enemies[Random.Range(0, enemies.Length)], Spawn3.transform.position, Spawn15.transform.rotation);
        Instantiate (enemies[Random.Range(0, enemies.Length)], Spawn1.transform.position, Spawn15.transform.rotation);
        yield return new WaitForSeconds(1.5f);
        Instantiate (enemies[Random.Range(0, enemies.Length)], Spawn5.transform.position, Spawn15.transform.rotation);
        Instantiate (enemies[Random.Range(0, enemies.Length)], Spawn7.transform.position, Spawn15.transform.rotation);
        yield return new WaitForSeconds(0.18f);
        Instantiate (enemies[Random.Range(0, enemies.Length)], Spawn6.transform.position, Spawn15.transform.rotation);
        yield return new WaitForSeconds(1.32f);
        Instantiate (enemies[Random.Range(0, enemies.Length)], Spawn9.transform.position, Spawn15.transform.rotation);
        Instantiate (enemies[Random.Range(0, enemies.Length)], Spawn11.transform.position, Spawn15.transform.rotation);
        yield return new WaitForSeconds(1.5f);
        Instantiate (enemies[Random.Range(0, enemies.Length)], Spawn13.transform.position, Spawn15.transform.rotation);
        Instantiate (enemies[Random.Range(0, enemies.Length)], Spawn15.transform.position, Spawn15.transform.rotation);
        yield return new WaitForSeconds(0.18f);
        Instantiate (enemies[Random.Range(0, enemies.Length)], Spawn14.transform.position, Spawn15.transform.rotation);
        yield return new WaitForSeconds(1.32f);
        //part3(10.5)
        Instantiate (enemies[Random.Range(0, enemies.Length)], Spawn1.transform.position, Spawn15.transform.rotation);
        yield return new WaitForSeconds(0.37f);
        Instantiate (enemies[Random.Range(0, enemies.Length)], Spawn15.transform.position, Spawn15.transform.rotation);
        yield return new WaitForSeconds(0.37f);
        Instantiate (enemies[Random.Range(0, enemies.Length)], Spawn3.transform.position, Spawn15.transform.rotation);
        yield return new WaitForSeconds(0.37f);
        Instantiate (enemies[Random.Range(0, enemies.Length)], Spawn13.transform.position, Spawn15.transform.rotation);
        yield return new WaitForSeconds(0.37f);
        Instantiate (enemies[Random.Range(0, enemies.Length)], Spawn5.transform.position, Spawn15.transform.rotation);
        yield return new WaitForSeconds(0.37f);
        Instantiate (enemies[Random.Range(0, enemies.Length)], Spawn11.transform.position, Spawn15.transform.rotation);
        yield return new WaitForSeconds(0.37f);
        Instantiate (enemies[Random.Range(0, enemies.Length)], Spawn7.transform.position, Spawn15.transform.rotation);
        yield return new WaitForSeconds(0.37f);
        Instantiate (enemies[Random.Range(0, enemies.Length)], Spawn9.transform.position, Spawn15.transform.rotation);
        yield return new WaitForSeconds(0.37f);
        Instantiate (enemies[Random.Range(0, enemies.Length)], Spawn6.transform.position, Spawn15.transform.rotation);
        yield return new WaitForSeconds(0.37f);
        Instantiate (enemies[Random.Range(0, enemies.Length)], Spawn10.transform.position, Spawn15.transform.rotation);
        yield return new WaitForSeconds(0.37f);
        Instantiate (enemies[Random.Range(0, enemies.Length)], Spawn4.transform.position, Spawn15.transform.rotation);
        yield return new WaitForSeconds(0.37f);
        Instantiate (enemies[Random.Range(0, enemies.Length)], Spawn12.transform.position, Spawn15.transform.rotation);
        yield return new WaitForSeconds(0.37f);

and it goes on… but for some reason the times do not match up with the song time…

I don’t know how to do it but see if you can find any thing about vib-ribbon. I know they found a way to let players use any music & the game read ahead of the music coming out the speakers to see what was happening so it had time to generate the content.

^I actually spent a bunch of time figuring things out and I figured a way to just use invoke the spawn enemies at different spawn points at a set time. Still a lot of repetitive coding but it gets the job done -_-