I am making a Rhythm game and I am looking to change the time when the song reaches a certain point; but I do not know how to do this.
This is my array controlling what note is being played (1=Z,2=X,3=N,4=M):
var lvlArray1:Array = new Array(0,2,0,0,0,2,0,0,0,2,0,0,0,2,0,0,0,
3,0,0,0,3,0,0,0,3,0,0,3,0,0,0,0,0,
0,0,0,0,0,1,4,1,4,0,0,0,0,0,0,0,0);
And to control my tempo I have:
//sTempo is how many frames it takes before
//a note is created. Because it's 12, and
//the frame rate is 24, it will take a half of a second
//for a note to be made
var sTempo:Number = 12;
How would I go about changing the tempo to say 6 when the 40th note is played (where the 1,4,1,4 starts)
I feel like this might be something incredibly simple, but my mind is just blank.
Thank you for your time!
Without having much code to go on, this is what I've cooked up.
You can have a separate Dictionary of tempo changes that correspond to the index of the lvlArray1. And you can check that dictionary whenever you're about to create a new note.
Example:
var tempoChanges:Dictionary = new Dictionary();
tempoChanges[39] = 6; // specify a tempo change to 6 for the 40th note (index 39)
// check to see if there's a tempo change for index i
if(tempoChanges[i] != undefined)
{
// if there is, change the tempo to that value
sTempo = tempoChanges[i];
}
Related
Has anyone been able to loop a MIDI file without problems on IOS9 Beta?
As soon as I try to loop by setting numberOfLoops to 0 in MusicTrackLoopInfo, it locks up the app by sending random MIDI to the player. I've reported it, but am wondering if anyone has found a work around. The same code works perfectly under all other iOS versions.
MusicTrackLoopInfo loopInfo;
loopInfo.loopDuration = loopLength;
loopInfo.numberOfLoops = 0;
OK I just heard iOS9 will ship with this bug in it. Terrible.
Here is a work around.
Don't set numberOfLoops at all, OR set numberOfLoops = 1; // means loop once
Now make a variable (i.e. myVariableToKeepTrackOfAddedCopies) that keeps track of the number of times you will actually perform the following:
In your MIDIReadProc at some point BEFORE the track has finished playing, do the following:
// Copy the track to itself - effectively doubling the length
MusicTrack theTrack=nil;
MusicTrackGetProperty(theTrack, kSequenceTrackProperty_TrackLength, &trackLen, &trackLenLen);
trackLen = 4.0; //<-- this is your real track length
MusicTrackCopyInsert(theTrack, 0, trackLen, theTrack, 0);
myVariableToKeepTrackOfAddedCopies++;
So now your track is twice as long before it ends and the track will continue. This will work the same as looping except you are taking up more memory since you are making the track length longer after each iteration.
When you stop the sequence/track, cut the track back to the original size.
MusicTrackCut(theTrack, 4.0, 4.0 + (4.0*myVariableToKeepTrackOfAddedCopies));
MusicTrackGetProperty(theTrack, kSequenceTrackProperty_TrackLength, &trackLen, &trackLenLen);
Irritating, but it works. I just verified on iOS9 beta 5. Hope it helps.
This is fixed as of iOS release 9.2
Oddly enough, the tempo track does not seem to have this problem. The following code does not lock up for me:
MusicTrack tempoTrack;
OSSTATUS = MusicSequenceGetTempoTrack(self.sequence, &tempoTrack);
SafeMusicTrackClear(tempoTrack); //calls into MusicTrackClear
MusicTrackNewExtendedTempoEvent(tempoTrack, 0, self.tempo * self.tempoMultiplier);
MIDIMetaEvent timeSignatureMetaEvent;
timeSignatureMetaEvent.metaEventType = 0x58;
timeSignatureMetaEvent.dataLength = 4;
timeSignatureMetaEvent.data[0] = 1;
timeSignatureMetaEvent.data[1] = 4;
timeSignatureMetaEvent.data[2] = 0x18;
timeSignatureMetaEvent.data[3] = 0x08;
MusicTrackNewMetaEvent(tempoTrack, 0, &timeSignatureMetaEvent);
MusicTrackLoopInfo loopInfo;
loopInfo.loopDuration = 0.25f;
loopInfo.numberOfLoops = 0;
MusicTrackSetProperty(tempoTrack, kSequenceTrackProperty_LoopInfo, &loopInfo, sizeof(loopInfo));
Unfortunately, it does not seem that the tempo track can actually play notes.
UPDATE:
After a few hours of digging around and trying to figure out a better solution to the problem, I settled on manually looping by sending a user event at the end of my sequence.
My sequence is created in a method...
-(void) loadPacketsForLoopingSequence {
SafeMusicTrackClear(loopingTrack); //calls into MusicTrackClear
// calculate timestampToPlaySequenceAt -- the starting point of the current sequence iteration, probably in the past, based on MusicPlayerGetTime and the length of the sequence -- here
// calculate timestampToPlayNextSequenceAt -- the starting point of the next sequence iteration, based on MusicPlayerGetTime and the length of the sequence -- here
// a single iteration of the notes get added to loopingTrack here, starting at timestampToPlaySequenceAt
MusicEventUserData event;
event.length = 1;
event.data[0] = 0xab; //arbitrary designation
// -0.5 to make sure we still have time to do the next step in the callback
MusicTrackNewUserEvent(loopingTrack, timestampToPlayNextSequenceAt - 0.5, &event);
}
...which is called again in the callback:
void sequenceCallback(void* inClientData,
MusicSequence inSequence,
MusicTrack inTrack,
MusicTimeStamp inEventTime,
const MusicEventUserData* inEventData,
MusicTimeStamp inStartSliceBeat,
MusicTimeStamp inEndSliceBeat) {
CSMidiMusicPlayer* musicPlayer = (CSMidiMusicPlayer*)inClientData;
[musicPlayer loadPacketsForLoopingSequence];
}
The callback has to be registered during sequence init using MusicSequenceSetUserCallback.
The -0.5 kludge could probably be eliminated altogether by examining the parameters in sequenceCallback and modifying loadPacketsForLoopingSequence to accept a parameter, but I haven't gotten that far yet.
I like this solution because it stays in MIDI time and doesn't modify the MIDI file in unexpected, stateful ways. (New notes basically get streamed in when you get close enough to a loop marker.)
so this is my first time here. Have looked around if this question has been answered, and it has, but not clear enough for me. Sorry for the potential double post.
I am trying to get enemies on the screen. They spawn at random positions, as you can see below, but... they spawn on top of their previous spawned enemy. The answers I read include putting it into an array, but I did, right? I'm a bit confused and working on this for too long, might be that too.
Thanks in advance!
function enemySpawn(e:TimerEvent) {
var enemyAxis:int = Math.round(Math.random()); // determines the x or y axis (0 or 1)
var enemyPos1:int = Math.round(Math.random()) * 600; // spawning it outside the stage (0 or 600)
var enemyPos2:int = Math.floor(Math.random() * 600); // spawning it at random around the stage border (0 through 600)
// spawning the enemy at correct axis
addChild(_enemy);
if(enemyAxis == 0){
// we declare 0 = x-axis, then either position 0 or max-width, plus the enemy's width.
_enemy.x = enemyPos1;
_enemy.y = enemyPos2;
} else
if(enemyAxis == 1){
// we declare 1 = y-axis, then either position 0 or max-height, plus the enemy's height.
_enemy.y = enemyPos1;
_enemy.x = enemyPos2;
}
enemyContainer.push(_enemy);
Not sure that I understood you correctly, but calling addChild is not enough to create a new instance of MovieClip. It just adds it to the target container (or does nothing, if the MC is already in that container).
If you want to spawn several enemies simultaneously, you should create new instances of your MC using the new keyword prior to calling addChild:
var enemy:MovieClip = new Enemy();
addChild(enemy);
// _enemies is an array/vector that contains all created enemies;
// it is not necessary, but helps to access the enemy later, when
// the call of enemySpawn() function inside which the enemy was created
// has ended
_enemies.push(enemy);
To be able to do this, you'll need to enable AS3 linkage for the Enemy symbol in the Library. See this answer.
Hey I am using GetUserMedia() to capture audio input from user's microphone. Meanwhile I want to put captured values into an array so I can manipulate with them. I am using the following code but the problem is that my array gets filled with value 128 all the time (I print the results in console for now), and I can't find my mistake. Can someone help me find my mistake?
//create a new context for audio input
context = new webkitAudioContext();
var analyser = null;
var dataarray = [];
getLiveInput = function() {
navigator.webkitGetUserMedia({audio: true},onStream,onStreamError);
};
function onStream(stream)
{
var input = context.createMediaStreamSource(stream);
analyser = context.createAnalyser();
var str = new Uint8Array(analyser.frequencyBinCount);
analyser.getByteTimeDomainData(str);
for (var i = 0; i < str.length; i++) {
var value = str[i];
dataarray.push(value);
console.log(dataarray)
}//end for loop
}//end function
function onStreamError(e) {
console.error('Streaming failed: ', e);
};
The values returned from getByteTimeDomainData are 8 bit integers, from 0 to 255. 128, which is half way, basically means "no signal". It is the equivalent of 0 in PCM audio data from -1 to 1.
But ANYWAY - there are a couple problems:
First, you're never connecting the input to the analyser. You need input.connect(analyser) before you call analyser.getByteTimeDomainData().
The second problem isn't with your code so much as it's just an implementation issue.
Basically, the gotStream function only gets called once - and getByteTimeDomainData only returns data for 1024 samples worth of audio (a tiny fraction of a second). The problem is, this all happens so quickly and for such a short period of time after the stream gets created, that there's no real input yet. Try wrapping the analyser.getByteTimeDomainData() call and the loop that follows it in a 1000ms setTimeout and then whistle into your microphone as soon as you give the browser permission to record. You should see some values other than 128.
Here's an example: http://jsbin.com/avasav/5/edit
I had a hard time trying to word my question properly, so i'm sorry if it seems confusing. Also i'm using the flixel library in flash builder. It may not be that important butcause probably anyone that knows a little more than me or even a little AS3 could probably see what i'm doing wrong.
Anyway, what i'm trying to do is basically create 10 instances of this square object I made. all I have to do is pass it an x an y coordinate to place it and it works. so ive tested if i just do:
var testsquare:Bgsq;
testsquare = new Bgsq(0,0);
add(testsquare);
it works fine and adds a square at 0,0 just like i told it to, but i want to add 10 of them then move the next one that's created 25 px to the right (because each square is 25px)
my problem is that I only ever see 1 square, like it's only making 1 instance of it still.
anyone possibly have an idea what I could be doing wrong?
var counter:int = 0;
var bgsqa:Array = new Array;
for (var ibgs:int = 0; ibgs < 10; ibgs++)
{
bgsqa[counter] = new Bgsq(0,0);
bgsqa[counter].x += 25;
add(bgsqa[counter]);
counter++;
}
There's a lot you're doing wrong here.
First off, you're using a pseudo-iterator (counter) to access array elements through a loop instead of, well, using the iterator (ibgs).
Second, I don't see anything in the array (bgsqa) you're iterating through. It's no wonder you're having problems. Here's what you should do.
var bgsqa:Array = [];
for(var i:int=0;i<10;i++)
{
var bgsq:Bgsq = new Bgsq(i * 25, 0);
add(bgsq);
bgsqa.push(bgsq);
}
That should probably do it if your post is accurate.
for (var ibgs:int = 0; ibgs < 10; ibgs++)
{
bgsqa[counter] = new Bgsq(0,0);
bgsqa[counter].x = counter * 25;
add(bgsqa[counter]);
counter++;
}
They start at 0, so applying += is simply adding 25 to 0. This should do the trick.
I'm trying to convert the byteArray of a Sound Object to an array with floats. The Sound Object plays back fine & at full length, but the float Array i get from it is cut off (but sounds correct), so i must be doing something wrong in the conversion:
var s:Sound = mySound;
s.play(); // plays fine
var bytes:ByteArray = new ByteArray();
bytes.endian = Endian.LITTLE_ENDIAN;
s.extract(bytes, s.bytesTotal, 0);
var leftChannel:Array = new Array();
var rightChannel:Array = new Array();
bytes.position = 0;
while (bytes.bytesAvailable)
{
leftChannel.push(bytes.readFloat());
rightChannel.push(bytes.readFloat());
}
and this is what i get:
The top two channels are the original Sound Object.
The lower two is the float Array Data. I aligned them so you can see that the beginning is cut off and obviously the length is incorrect.
Thanks for any answers...
ok there were two problems:
the mp3 file i was importing was somehow corrupt, that caused the beginning to be cut off
the length i defined to extract was not correct, to find the full sound length use
var numTotalSamples:Number = int(s.length * 44.1); //assuming 44.1kHz sample rate
then:
s.extract(bytes, numTotalSamples, 0);