QBPlay - QuickBasic's Play-Befehl

Anwendungen, Tools, Userlibs und anderes nützliches.
Benutzeravatar
Froggerprogger
Badmin
Beiträge: 855
Registriert: 08.09.2004 20:02

QBPlay - QuickBasic's Play-Befehl

Beitrag von Froggerprogger »

Update!! Auf Version 1.5!
- Nun ist die Lib endlich auch PB4-tauglich!

-------------------------------------------------------

Moinsen!
Die QBPlay-Funktion ermöglicht das Abspielen der Lieder, die man in QBasic mit der Play(...)-Funktion erstellen konnte. Darüberhinaus gibt es einige weitere Funktionalitäten, z.B.:
- mehrere 'Instrumente' (Sinus/Rect/.../Organ/ChurchOrgan) :allright:
- mehrere Tracks zu einem einzigen zusammenmixen (für Mehrstimmigkeit)
- direkt als PB-Sound abspielbar, oder Export als WAV-Datei

QBPlay gibt es sowohl als Source, als auch als UserLib/Resident-Kombination zusammen mit ein paar Beispielen:
(bisserl zu viele Zeilen, daher externer Link:)
http://www.2mal2mal.de/public/purebasic ... ay_1.5.zip (.zip-Datei)
http://www.2mal2mal.de/public/purebasic/libs/QBPlay_1.5 (zip-Inhalt entpackt)

Zudem gibt es hier weitere Beispielsongs :
www.2mal2mal.de/public/purebasic/libs/QBPlay_Songs
Zuletzt geändert von Froggerprogger am 08.09.2007 14:14, insgesamt 3-mal geändert.
!UD2
Benutzeravatar
bobobo
jaAdmin
Beiträge: 3873
Registriert: 13.09.2004 17:48
Kontaktdaten:

Beitrag von bobobo »

Code: Alles auswählen

InitSound()
;/ example 3
*q1.QBSong = QBPlay("o3 ML l16 ccp      ccp      ccp      ccp      cgp      ggp      gcp      ccp      ccp      ccp      ccp      ccp      cgp      ggp      gce      T80 g<cp8", 2, 100, 0, #QBPlay_Tone_Sin,10, 10)
*q2.QBSong = QBPlay("o4 ML l16 cep      gep      cep      gep      gfg      fdp      fef      ecp      cep      gep      cep      gep      gfg      fde      dce      T80 g<cp8", 2, 100, 0, #QBPlay_Tone_Sin, 10, 10)
*q3.QBSong = QBPlay("o1 ML l16 c<c>c    c<c>c    c<c>c    c<c>c    c<g>g    g<g>g    g<g>g    c<c>c    c<c>c    c<c>c    c<c>c    c<c>c    c<g>g    g<g>g    g<c>c    T80 c<c4", 2, 100, 0, #QBPlay_Tone_Tan, 10, 10)
*q4.QBSong = QBPlay("o2 ML l16 c>c>c o2 c>c>c o2 c>c>c o2 c>c>c o2 c>g<g o2 g>g>g o2 g>g>g o2 c>c>c o2 c>c>c o2 c>c>c o2 c>c>c o2 c>c>g o2 c>g>g o2 g>g>g o2 g>c>c o2 T80 MLc", 2, 100, 0, #QBPlay_Tone_Organ, 10, 10)

QBPlay_Mix(*q1, *q2, 0)
QBPlay_Mix(*q1, *q3, 0)
QBPlay_Mix(*q1, *q4, 0)

QBPlay_Start(*q1, 0)

Delay(*q1\lengthMs)

filename.s = SaveFileRequester("Save it (or cancel)", "C:\QBPLAY_SuO.wav", "*.wav|*.wav", 0)
If filename 
    If QBPlay_WriteToFile(*q1, filename) = 0
        MessageRequester("", "Couldn't save file to disc.", 0)
    EndIf
EndIf
QBPlay_Free(*q1)
zick
‮pb aktuel 6.2 windoof aktuell und sowas von 10
Ich hab Tinnitus im Auge. Ich seh nur Pfeifen.
Benutzeravatar
Froggerprogger
Badmin
Beiträge: 855
Registriert: 08.09.2004 20:02

Beitrag von Froggerprogger »

zick ??

Bitte nicht zuviele Informationen :wink:

Ich denke, Du meinst, das zickt ?

Mist, und ich dachte, dass sei selbsterklärend :D Aber wie auch...

Also:
Wenn man die Lib-Dateien nicht 'installiert', also die Lib in das Lib-Verzeichnis kopiert, und die Resident in das Resident-Verzeichnis (Details zur 'Installation' siehe Readme.txt) , dann muss man die Dateien per IncludeFile einbinden. Dabei allerdings geht die Möglichkeit optionaler Parameter verloren, dass heißt, mann muss dann jedesmal die richtige Funktion raussuchen, in deinem Fall wäre das QBPlay4(...) bei dieser Anzahl Parameter.

Aus QBPlay(...) QBPlay2(...) QBPlay3(...) QBPlay4(...) wird dann innerhalb einer Lib die Funktion QBPlay(...) mit optionalen Parametern.

Ich werde da gleich mal einen Hinweis drauf in den Examples für reinsetzen, so dass man auch per IncludeFile ohne weiteres testen kann...

[edit]
so, habe geupdatet. Die Lib heißt jetzt auch nicht mehr QBPlay2Wav, sondern nur QBPlay.
Es finden sich jetzt 2 EXAMPLE-Files:
- 1 dafür, wenn man die Lib installiert hat
- 1 dafür, wenn man das nicht möchte.
Außerdem hatte ich einen kleinen, aber wichtigen Vertipper in der Readme.txt, (darin bat ich den Anwender, die Source-Datei in das UserLibraries-Verzeichnis zu kopieren :shock: :) )
... also, wie Fred sagen würde:
Fixed.
[/edit]
!UD2
Benutzeravatar
Froggerprogger
Badmin
Beiträge: 855
Registriert: 08.09.2004 20:02

Beitrag von Froggerprogger »

:lol:
Du meintest mit zick wohl doch nicht, dass das nicht funktioniert, sondern dass es Dir gefällt ??

Dein Code oben funktioniert schließlich einwandfrei (und klingt suuper :allright: ) , ich war nur wegen des ;- example3 auf dem falschen Dampfer. Naja, hat aber ja nicht geschadet. :D
!UD2
Benutzeravatar
Froggerprogger
Badmin
Beiträge: 855
Registriert: 08.09.2004 20:02

Beitrag von Froggerprogger »

Ich glaube, ich werde arbeitslos und mache von morgens bis abends PlayStrings :mrgreen:

Mein erster 'richtiger' Song:

Code: Alles auswählen

;/ "Years Ago" (0:52) - by Froggerprogger ;-)
InitSound()

melodie1.s = "t160 XI0 XS200 MN O3 L8 p e  de   c4   >h4  a<e  d e  c4. L16dc>h2        h4   a4   g4.    a8  h4.L16<c>ha8<a8>a2    L8a g  f4.    g  a2        L16efgf gaga hah<c> h<cdc dede fefg fgag ahMLL8<c"
melodie2.s = "t160 XI0 XS500 MN O4 L8 p e  e8.e16 a4   eMSe  p8e8 e8e16MLa8p32MSe16MLa8p32e16MN<c8> L4g   L8dg  >h<d>g h  d4   gh4 <dg4  f4   cf>  a<f> f<MSf4 MNf4 c >a4  <f4  p4     L4d L4d L8gh4h4L16gdada#dMLh4"
bassloop.s = "t160 XI0 XS200 MN O0 L8 a<a> a<a> a<a> a<a> a<a> a<a> a<a> a<a> g<g> g<g> g<g> g<g> g<g> g<g> g<g> g<g> f<f> f<f> f<f> f<f> f<f> f<f> f<f> f<f> g<g> g<g> g<g> g<g> g<g> g<g> g<g> g<g>"
ticks.s    = "t160 XI0 XV15 XS100 M8 O4 L16 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa gggggggggggggggggggggggggggggggg ffffffffffffffffffffffffffffffff gggggggggggggggggggggggggggggggg"

ending1.s = "t80 XI6 XS2000 MN O1 L1a"
ending2.s = "t160 XI0 XS1000 MN O0 L8 a<a> a<a> a<a> a<a> a<a> a<a>> L1a"
ending3.s = "t80 XV30 XI6 XS2000 MN O4 L1a"

*melodie = QBPlay(melodie1 + melodie2 + ReplaceString(ReplaceString(melodie1, "XI0", "XI1"), "O3", "O4") + ReplaceString(melodie2, "XI0", "XI1") + ending1, 2)
*bass    = QBPlay(bassloop + bassloop + bassloop + bassloop +  ending2, 2)
*ticks   = QBPlay(ReplaceString(ticks, "XV15", "XV0") + ReplaceString(ticks, "O4", "O5") + ticks + ReplaceString(ticks, "O4", "O5") +  ending3, 2)

*song = QBPlay_Mix(QBPlay_Copy(*melodie), *bass, 0)
QBPlay_Mix(*song, *ticks, 0)

QBPlay_Start(*song, 0)
Delay(QBPlay_GetLengthMs(*song) + 1000) 
Ab sofort setze ich ab und an mal Songs (als MP3 und Sourcecode) online auf:
http://www.2mal2mal.de/public/purebasic ... lay_Songs/
:D
!UD2
Benutzeravatar
MVXA
Beiträge: 3823
Registriert: 11.09.2004 00:45
Wohnort: Bremen, Deutschland
Kontaktdaten:

Beitrag von MVXA »

Anstatt das in eine MP3 zu verfrachten kannst du doch gleich einen Miniplayer schreiben. Das hat dann den Vorteil das es nicht so groß ist und du man hätt n schicken neuen miniplayer.
Bild
Benutzeravatar
Froggerprogger
Badmin
Beiträge: 855
Registriert: 08.09.2004 20:02

Beitrag von Froggerprogger »

Yeah, was ne Party :mrgreen:
Ich muss zwar gleich wieder aufstehen, aber wollte unbedingt erst noch YearsAgoEx = Years Ago Extended Version (1:38 ) fertig stellen, welches nun über einen wunderbaren Mittelteil verfügt. Das Errechnen dauert bei mir insgesamt schon ca. 1 ganze Minute (im Mittelteil läuft ein 16tel-Arpeggio mit 1,5-Sekunden-Sustain) !

Habs mal raufgeladen, damit ich endlich schlafen gehen kann...
(aber vorher hör ichs mir nochmal an :D )

@LittleFurz
Das Problemchen bei der derzeitigen Version ist, dass sie zuerst die gesamte Datei zuenderechnen muss, bevor man sie anhören kann. Ich werde aber irgendwann mal eine während-des-rechnen-schon-anhör-funktion nachrüsten (ist dafür schon tauglich, aber noch nicht fertig)

btw: ...da sehen selbst MP3's blass aus ;-)
QBPLAY_YearsAgoEx.mp3 hat 788kByte Größe, die Beschreibung der Datei in vollem 44100Hz stereo ist aber nur etwa 3kB groß...
!UD2
Benutzeravatar
MVXA
Beiträge: 3823
Registriert: 11.09.2004 00:45
Wohnort: Bremen, Deutschland
Kontaktdaten:

Beitrag von MVXA »

joo... hab ich gemerkt und wärend das Lied so berechnet wird, nuzt du mein Prozessor zu 100% aus... der hat auch noch andere Aufgaben zu erledigen (windows ausführen, PB Compiler, jaPBe, WinAmp, mich am leben erhalten, etc..). Sonst ist die Lib aber echt gut !

P.S. Nachts schreib ich immer son schrott :freak: (Das deine Lib aber mein Prozessor zu 100% auslastet stimmt aber, steht im Task manager :wink: )
Bild
ShadowTurtle
Beiträge: 114
Registriert: 11.09.2004 07:58
Wohnort: Mannheim
Kontaktdaten:

Beitrag von ShadowTurtle »

Es Fehlt jetzt nur noch einen Prima Sound Editor der die volle Funktionsvielfalt von play ausnutzt. Und dies ist nicht mal wenig.

Aber respekt, echt.

cu
Benutzeravatar
Froggerprogger
Badmin
Beiträge: 855
Registriert: 08.09.2004 20:02

Beitrag von Froggerprogger »

Ooops. An die "Einbettung in eine moderne Multitasking-Umgebung" habe ich gar nicht gedacht (sondern: "Platz da, hier kommt 'Play' ")
Werde ich noch ändern.

Bevor ich einen Sound Editor bastele, werde ich zunächst noch die Funktionsvielfalt erhöhen. Bisher sind mir eingefallen:

R = Reset to Anfangszustand (Instrument,Attack,Sound,Legato, Length, Octave,...)
_ = Haltebogen zwischen zwei (denselben) Noten (um sie zu verlängern)
|: (...) : | = Wiederholungszeichen
|: (...) : |[x/y;z/q] = Wiederholung mit Ersetzungen im Teil (z.B. für Instrument/Oktave-Änderungen, hier x durch y und y durch q)
[x/y;z/q] = Ersetzungen bis zum Ende des Songs (x durch y und y durch q)
[] = alle Ersetzungen aufheben.
(also R[] = Reset und alle Ersetzungen aufheben)
Yxx = 'Y' = sYnchronize, xx = integer
Beim Mixen von Songs werden (chronologisch) dieselben Yxx-Marken aneinandergelegt, so kann man z.B. eine 'Spur' auch mal längere Zeit aussetzen lassen, ohne sie mit der entsprechenden Anzahl Pausen aufzufüllen.
\* (...) *\ = Kommentar
?xx = Marker mit ID xx. Wird auch als Marker in die WAV-Datei geschrieben.
?/*Titel*/xx = Marker mit ID xx. Wird zusammen mit 'Titel' in die WAV-Datei geschrieben.
(Bei beiden weiß ich noch nicht, ob es Sinn macht, die ID explizit angeben zu müssen, vielleicht ist es besser, das automatisch zu machen)
|| = Ende der 'Spur' => Springe zeitlich wieder an den Anfang und führe R[] aus. Alles folgende wird dem bereits bestehenden zugemischt: So lassen sich mehrere Spuren in nur einem String erzeugen.
KEY[PlayStringOhneNoten] = setze Keyframe. Von diesem aus werden bis zum nächsten alle darin enthaltenen Angaben zeitlich linear interpoliert. So lassen sich dann Lautstärkeverläufe, etc. realisieren.

Dann steht auf der ToDo-Liste, der buffered Stream-Output (entweder per fmod, oder wirklich 'per Hand' mit WinAPI), so dass man den Song gleich starten & hören kann, während er im Hintergrund weiter berechnet wird.
(Das klappt dann aber nur, wenn man mit QBPlay() direkt einen String wiedergeben möchte, nicht wenn man erst mehrere separate erzeugt, und später im Programm per QBPlay_Mix mixt. Vielleicht bekomme ich das aber auch mit dem || so hin, dass man die QBPlay_Mix - Funktion gar nicht mehr braucht, und die Sofortwiedergabe damit funktioniert.)

Achso, nochwas: Anstelle eines Strings kann eine Textdatei oder ein Pointer an QBPlay übergeben werden (u.a. um das 64k-Limit von PB zu knacken).

Natürlich folgen dann noch einige weitere Instrumente, sowie ein Minimini - Drumset, und bis zu 16(?) Callback-Funktionen für nachträglich selbst-erstellbare Instrumente. (Die Funktion bekommt einfach dieselben Daten wie QBPlay_WriteNote() übermittelt und erwartet einen generierten Sound.)

Außerdem einige hauseigene Effekte und andere Samplewertveränderungen (Normalize, FadeIn, FadeOut, Chorus, Echo, Reverb), welche auf den gesamten Song angewandt werden.

Dann erfolgt eine MIDIfizierung in beide Richtungen (MIDI2PlayString und PlayString2MIDI)

Auch wird dann ein eigenes Sampleformat eingeführt, welches sich über PlayStrings abspielen läßt.

Und schließlich folgt der Mehrspur-Soundeditor.

Dann werden die ersten Mega-Retro-Platten herausgebracht, welche ausschließlich mit PlayStrings arbeiten (Funktionsaufruf lediglich: QBPlay(...) ) und die Charts stürmen. Zusammen mit dem noch ausstehenden 'Vocalizer'-Befehl ( VOX[DiesenTextBitteSingen] ) sicher kein Problem. Eine CD-ROM dürfte dann so ca. einige Jahre Musikmaterial enthalten können, wenn man nur die PlayStrings zusammen mit einem kleinen Player draufpackt.

Hat sonst noch wer Ideen ?

Abgabetermin ist der 11.11. (mal sehen, welches Jahr 8) )
!UD2
Antworten