Zurück   Flashforum > Flash > ActionScript > ActionScript 3

Antwort
 
LinkBack Themen-Optionen Ansicht
Alt 10-12-2008, 09:15   #1 (permalink)
Neuer User
 
Benutzerbild von Raphael79
 
Registriert seit: Sep 2004
Ort: Hamburg
Beiträge: 35
Sound Sequencer Problem / Sound Timing

Ich möchte einen kleinen Sound-Sequencer bauen und bekomme keinen sauberen Takt hin.

Ich habe mir überlegt, dass es einen Taktgeber gibt, der z.B. jeden Takt ein Event dispatched auf dem man verschiedene Sounds starten kann.

Die Idee ist, dass der User eine Auswahl an Sounds hat und diese an- und ausschalten kann.
Hat man einen Sound, welcher 4 Takte lang ist, wird dieser dann erst nach 4 Takten neugestartet. Eine Basedrum, die jeden Takt läuft, würde dann logischer weise jeden Takt gestartet werden.

Mann kann zwar einfach ausrechnen wie lang ein Takt ist. Z.B. für 120 BPM: 60 / 120 * 1000 = 500ms. Aber leider ist die Timer-Klasse so ungenau, dass man damit keinen sauberen Takt hinbekommt. Ein ENTER_FRAME Event kommt natürlich auch nicht in Frage, da die Events sich ja immer in dem Frame Raster bewegen, welches sich je nach CPU Auslastung auch noch verändert.

Auf der Suche nach Lösungen habe ich verschiedene Ansätze gefunden:

Eine Lösung für Flash MX: http://www.actionscript.org/resource...ing/Page1.html
Leider funktioniert die nicht mehr in AS3, da das SOUND_COMPLETE Event unsauber kommt.

Eine Lösung für AS3: http://glossar.hs-augsburg.de/Konsta...ActionScript_3)
Habe ich nicht zum laufen bekommen. Der Artikel wird auch zur Zeit überarbeitet, also vielleicht stimmt da auch was nicht.

André's erste Synthis: http://blog.andre-michelle.com/2006/...iocyclebuffer/
In den Kommentaren bedanken sich die Leute für die Sources, ich kann sie nicht finden..? Ich will ja eigentlich auch keinen Sound erzeugen, sondern geladene mp3's zum richtigen Zeitpunkt starten.


Also mittlerweile sind wir auch soweit das Projekt für den FP10 zu kompilieren, wenn das eine Lösung bringen würde. Aber André Michelle's und Joa Ebert's Sequencer lief doch auch im FP9. Daher muss es doch eine Lösung geben.

Hat irgendjemand eine Idee, oder einen verständlichen Ansatz für mein Problem? Oder einen Tipp? Link?


Vielen Dank schon Mal!
Raphael
Raphael79 ist offline   Mit Zitat antworten
Alt 10-12-2008, 09:46   #2 (permalink)
\x3a\x6f\x29
 
Benutzerbild von [je]
 
Registriert seit: Apr 2004
Ort: paris
Beiträge: 806
Wenn du Samples zählst, statt einen Timer zu benutzen, bist du immer Sample-Exakt und hast keine Timing Probleme.

Wenn du bei 120 BPM also 500ms pro Takt hast kannst du das ausrechnen. Bei 44.1khz hast du 44100 Samples pro 1000ms. D.h. du hast alle 44100/2 Samples einen neuen Takt.
__________________
joa ebert
http://blog.joa-ebert.com/ - http://www.joa-ebert.com/
[je] ist offline   Mit Zitat antworten
Alt 10-12-2008, 10:29   #3 (permalink)
[+]
 
Benutzerbild von André Michelle
 
Registriert seit: Dec 2002
Ort: cologne
Beiträge: 2.271
Zitat:
Also mittlerweile sind wir auch soweit das Projekt für den FP10 zu kompilieren, wenn das eine Lösung bringen würde.
Na dann!
__________________
aM

blog | laboratory | tonfall | processing

Audiotool.com
André Michelle ist offline   Mit Zitat antworten
Alt 10-12-2008, 10:32   #4 (permalink)
[+]
 
Benutzerbild von André Michelle
 
Registriert seit: Dec 2002
Ort: cologne
Beiträge: 2.271
Hier sind noch meine Beispiele von der MAX08
__________________
aM

blog | laboratory | tonfall | processing

Audiotool.com
André Michelle ist offline   Mit Zitat antworten
Alt 10-12-2008, 11:14   #5 (permalink)
Neuer User
 
Benutzerbild von Raphael79
 
Registriert seit: Sep 2004
Ort: Hamburg
Beiträge: 35
Also erstmal Danke für die Antworten. Allerdings bringen sie mich nicht so richtig weiter..

Wenn ich das richtig verstehe sollte man das also ungefähr so machen (mal eben schnell mit nested functions):

Code:
var sound : Sound = new Sound( );
var channel : SoundChannel;
var samplesAmount : int = 60 / 120 * 44100;
var samples : int;
var i : int;
var date1 : Date;
var date2 : Date;
						
function countSamples (event : SampleDataEvent) : void 
{
	samples = Math.min( 8192, samplesAmount );
	samplesAmount -= samples;
				
	for ( i = 0; i < samples ; i++ ) 
	{
		event.data.writeFloat( 0 );
		event.data.writeFloat( 0 );
	}
}
						
function onSoundComplete (event : Event) : void 
{
	date1 = new Date( );
	if(date2) trace( "sauberer takt. ms: " + (date1.getTime( ) - date2.getTime( )) );
	date2 = new Date( );
				
	samplesAmount = 60 / 120 * 44100;
	channel = sound.play( );
	channel.addEventListener( Event.SOUND_COMPLETE, onSoundComplete, false, 0, true );
				
	// starte andere sound-objekte, die auf diesem takt liegen
}
						
sound.addEventListener( SampleDataEvent.SAMPLE_DATA, countSamples, false, 0, true );
channel = sound.play( );
channel.addEventListener( Event.SOUND_COMPLETE, onSoundComplete, false, 0, true );
Oder ist dieser Ansatz falsch? Denn er ist nicht sauberer als wenn ich einen Timer benutze. Und dieser Ansatz ist für FP10, kann man Samples denn auch im FP9 zählen?

Wenn ich es richtig verstehe, dient mein Soundobjekt ja nur als Taktgeber. Die anderen Sound-Objekte sind ja normal geladene MP3's die einfach auf dem Takt gestartet werden. Oder ist das vom Ansatz schon falsch?

Gruß,
Raphael
Raphael79 ist offline   Mit Zitat antworten
Alt 10-12-2008, 11:29   #6 (permalink)
[+]
 
Benutzerbild von André Michelle
 
Registriert seit: Dec 2002
Ort: cologne
Beiträge: 2.271
Zitat:
Oder ist das vom Ansatz schon falsch?
Ja.

Du hast Zugriff auf jedes Sample. D.h. wenn du deine Samples ordentlich mitzählst, kannst du auch eine BassDrum an sampleexakter Stelle starten. Ohne weitere Timer.

Schau Dir bitte auch die Beispiele an. Dort findest du einiges, was du verwerten kannst.
__________________
aM

blog | laboratory | tonfall | processing

Audiotool.com
André Michelle ist offline   Mit Zitat antworten
Alt 10-12-2008, 11:46   #7 (permalink)
Neuer User
 
Benutzerbild von Raphael79
 
Registriert seit: Sep 2004
Ort: Hamburg
Beiträge: 35
Ok, also zähle ich die Samples nicht ordentlich? Welchen weiteren Timer meinst du?

Ich hab mir die Sourcen schon mal angeschaut, aber hab da nicht wirklich was rausziehen können. Komme da leider nicht weiter.

Hat jemand sonst das geblickt und hat Lust das mal an einem simplen Beispiel zu zeigen? FP9 und FP10? Sowas kann ja eigentlich keine Raketentechnik sein.. Sounds zum richtigen Zeitpunkt abspielen.. tsts
Raphael79 ist offline   Mit Zitat antworten
Alt 10-12-2008, 13:06   #8 (permalink)
vermisst ein e
 
Benutzerbild von kRizzl
 
Registriert seit: Oct 2007
Beiträge: 774
naja so trivial ists nicht. wie du schon rausgefunden hast, gibts beim naiven ansatz, einfach das Sound-objekt zu verwursten, keine zuverlaessige moeglichkeit - das allein ist ja schon schade genug. daher ist man gezwungen, sich die sounds neu zusammen zu basteln, was nen relativ hohen rechenaufwand fuer diesen task bedeutet.

voraussetzung fuer die sample-methode ist, dass deine sounds exakt gleich lang sind. also alle ein vielfaches einer gewissen anzahl samples haben, sonst musst du sie irgendwo abschnibbeln.
die sounds muessen soweit geladen sein, dass du zugriff auf die abzuspielenden samples hast, duerfte klar sein.

nun erzeugst du dir ein neues sound-objekt, dem du einen listener fuer das SampleDataEvent hinzufuegst. den ganzen vorgang startest du dann mit play() auf diesem mixer-sound-objekt.
innerhalb des listeners liest du mit extract() aus jedem deiner quell-sounds mindestens 2028 samples aus (das sind pro sample jeweils zwei floats bei stereo-klang).
hier ist zu beachten, dass dir extract() n bytearray fuellt und jeder float 4 byte gross ist (daher sind 2028 samples 2028*2*4 bytes gross, wenn du stereo verwendest).
diese samples aus den quellsounds summierst du auf und schreibst sie wie in deinem code oben ins data-property des events.

pro durchgelaufenem listener addierst du die anzahl geschriebener samples auf einen counter mit druff und hast damit immer die aktuelle position.

aber als erster schritt waere es vielleicht gut, alle quell-sounds in einen zu schreiben, die synchronisation kommt dann als naechster.. weil so trivial ist es dann wie gesagt doch nicht (;
__________________
krisrok.de

Geändert von kRizzl (10-12-2008 um 13:08 Uhr)
kRizzl ist offline   Mit Zitat antworten
Alt 10-12-2008, 13:25   #9 (permalink)
Neuer User
 
Benutzerbild von Raphael79
 
Registriert seit: Sep 2004
Ort: Hamburg
Beiträge: 35
Ah, das ist interessant!

Das bedeutet, dass ich gar nicht auf das SOUND_COMPLETE warte und dann die Soundobjekte mit play() starte, sondern ich lasse einen Sound als Taktgeber unendlich laufen und in dem SampleDataEvent.SAMPLE_DATA Listener hole ich mir von allen Sounds per extract() die Bytes und schreibe sie in meinen Taktgeber Sound!

Das ist die Antwort die ich brauchte. So verstehe ich jedenfalls schon mal das Grundprinzip besser. Werde das heute Abend mal austesten.

Das geht allerdings nur im FP10, oder? Weißt du wie man das im FP9 gemacht hat? André's Sequencer lief ja auch schon vor FP10 Zeiten..

Ach, und meinst du 2048 samples? Weil 2028 ja keine Zweierpotenz ist. Und wie kommst du eigentlich auf diese Mindestzahl (2028 oder 2048)? Man kann ja pro Event 512 bis 8192 Samples schreiben..


Dank und Gruß,
Raphael
Raphael79 ist offline   Mit Zitat antworten
Alt 10-12-2008, 13:30   #10 (permalink)
vermisst ein e
 
Benutzerbild von kRizzl
 
Registriert seit: Oct 2007
Beiträge: 774
natuerlich 2048.. gnarf wie ich auf die anzahl komm, weiss ich auch nicht. ich hatte im kopp, dass es zwischen 2048-8192 sein muessen.

das geht nur ab fp10, yep. die burschen da oben haben sich das schon im fp9 ueber nen cleveren hack ermoeglicht. ist allerdings noch rechenlastiger, hat aber inzwischen vielleicht sogar weniger latenz? (;
__________________
krisrok.de

Geändert von kRizzl (10-12-2008 um 13:32 Uhr)
kRizzl ist offline   Mit Zitat antworten
Alt 10-12-2008, 13:42   #11 (permalink)
Neuer User
 
Benutzerbild von Raphael79
 
Registriert seit: Sep 2004
Ort: Hamburg
Beiträge: 35
Ah ok, alles klar

Verdammt, ich war doch auf der FITC in Amsterdam dieses Jahr und habe mir angeschaut wie André das gehackt hat. Aber richtig dran erinnern kann ich mich nicht mehr..

Evtl. ist die FP10 Variante aber eh die performantere und saubere.
Werde das später mal austesten. Danke auf jeden Fall!
Raphael79 ist offline   Mit Zitat antworten
Alt 10-12-2008, 13:46   #12 (permalink)
[+]
 
Benutzerbild von André Michelle
 
Registriert seit: Dec 2002
Ort: cologne
Beiträge: 2.271
Ein praktisches einfaches Beispiel anhand eines Metronomes.

Code:
package  
{
	import flash.display.Sprite;
	import flash.events.SampleDataEvent;
	import flash.media.Sound;
	import flash.utils.ByteArray;
	import flash.utils.setTimeout;		

	/**
	 * @author aM
	 */
	public class Metronome extends Sprite 
	{
		static public const BLOCK_SIZE: int = 2048;
		
		private var _sound: Sound;

		private var _mPosition: int;
		private var _mDuration: Number;
		private var _mIndex: int;
		private var _mPhase: Number;
		private var _mDecay: Number;
		
		public function Metronome()
		{
			setTimeout( _init, 100 );
		}
		
		private function _init(): void
		{
			var tempo: Number = 130.0;
			
			_mDuration = ( .25 * 10584000.0 ) / tempo; // QUARTER NOTE LENGTH
			_mPosition = _mDuration;
			_mIndex = 0;
			_mDecay = 1.0;
			_mPhase = 0.0;
			
			_sound = new Sound();
			_sound.addEventListener( SampleDataEvent.SAMPLE_DATA, sampleData );
			_sound.play();
		}
		
		private function sampleData( event: SampleDataEvent ): void
		{
			var bytes: ByteArray = event.data;
			
			var amplitude: Number;
			
			for( var i: int = 0 ; i < BLOCK_SIZE ; ++i )
			{
				amplitude = Math.sin( _mPhase * Math.PI * 2 ) * _mDecay * .3;
				
				if( _mIndex == 0 )
					_mPhase += 1360 / 44100;
				else
					_mPhase += 880 / 44100;
				
				bytes.writeFloat( amplitude );
				bytes.writeFloat( amplitude );
				
				if( --_mPosition <= 0 )
				{
					if( ++_mIndex == 4 )
						_mIndex = 0;

					_mPhase = 0.0;
					_mPosition = _mDuration;
					_mDecay = 1.0;
				}
				else
				{
					_mDecay *= .9992;
				}
			}
		}
	}
}
__________________
aM

blog | laboratory | tonfall | processing

Audiotool.com
André Michelle ist offline   Mit Zitat antworten
Alt 01-04-2010, 16:54   #13 (permalink)
Neuer User
 
Registriert seit: Sep 2003
Beiträge: 658
nice!
und wo/wie mische ich dann einen zweiten loop dazu?
headkit ist offline   Mit Zitat antworten
Antwort

Lesezeichen

Stichworte
beat, sequencer, sound, takt, timing

Themen-Optionen
Ansicht

Forumregeln
Es ist Ihnen nicht erlaubt, neue Themen zu verfassen.
Es ist Ihnen nicht erlaubt, auf Beiträge zu antworten.
Es ist Ihnen nicht erlaubt, Anhänge hochzuladen.
Es ist Ihnen nicht erlaubt, Ihre Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks sind an
Pingbacks sind an
Refbacks sind an



Alle Zeitangaben in WEZ +1. Es ist jetzt 16:42 Uhr.

Domains, Webhosting & Vserver von Host Europe
Unterstützt das Flashforum!
Adobe User Group


Copyright ©1999 – 2012 Marc Thiele