I would separate these into their own algorithm. I would evaluate each variable one at a time and come up with a scale that determines the value for the next wave. numBricks = f(waveNumber).
Type of Bricks would have to be based on a sliding two-point scale where you have min and max values that increase but this would have to be done extremely slowly and there would eventually have to be an upper limit. If that doesn't work, you can base the scale's starting point on the current level of the players power-up. If they do 10 damage then start spawning 10-hit bricks to 50-hit bricks. You can't overpower or under-power so it all has to be relative to the players variables. Just a little stronger than the player's current variables.
The speed of bricks will also eventually reach a limit as they cannot fall faster then the player can see or the height of the screen so I would say the more hits a brick needs, based on player's strength, the slower it falls. That's a simple algorithm.
How often power-up spawn can be the greater the wave the less often the power-ups appear or based on the strength of the player. The stronger they are the less they spawn. Or have it spawn power-ups over random time intervals.
You want to make the game fun not just increase all the variables until they player is overwhelmed. Or maybe you do? I would make all variables relative to the player and the wave level.
Maybe try dividing the players variables by the wave level and using those values as scales?
or try using 1/wave to give you a unit scale to work with. The number gets smaller as the wave increases and this can be multiplied by other numbers to give you your values. Or maybe look into training a genetic-algorithm or neural-net that takes the player's variables and wave number to generate those values for you.
Hope that gives you some ideas.
Remelic