Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

[pascal] midi toon aanhouden zonder loopen

Pagina: 1
Acties:

  • link0007
  • Registratie: Augustus 2006
  • Niet online
Hallo,

Sorry voor de vage titel, maar ik kan niet echt een passende titel vinden voor dit probleem.

Ik ben sinds kort begonnen met het schrijven van een 'piano' in turbo pascal 7.


Nu gebruik ik voor de toetsaanslagen een case-of statement over de getkey-functie.

In die case-of statement zet ik de noot aan, schrijf ik de noot op het scherm, en zet ik de noot uit.

In een notendop (zonder omliggende procedures, behalve die waar het probleem zit) ziet het programma er zo uit:

Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[...]
Procedure Keys;
Begin
    KeyMap:=ReadKey;  {stop de waarde van ReadKey in variabele KeyMap);
    Case KeyMap Of
    '~' : Quit:=true;  {beëindig programma}
    '2' : Begin
        SetNoteOn(1,54,100); {Zet noot F sharp 4, midi 54, aan op kanaal 1 met velocity=100}
        Writeln('F Sharp 4'); {Schrijf de gedrukte noot uit}
          end;
    end;
end;



Begin
    GMPort:=$331
    ResetGM;
    repeat
       keys;
    until quit;
end.



Als ik nu dus een toon langer aansla dan "een bepaalde tijd" (maximale toonduur misschien?!), gaat de noot lussen maken. Dus tringggggg-trrrrrrrrrrrring.

Hoe kan ik ervoor zorgen dat er pas een nieuwe noot aangeslagen kan worden wanneer de vorige los gelaten is (en dus geen toetsen worden gedrukt)?


Ik heb al geprobeerd variabelen in te voegen die tijdens het drukken van een knop een bepaalde waarde krijgen, maar hij moet juist wél ingedrukt kunnen blijven.. de toon moet zich alleen niet herhalen.

Ook heb ik geprobeerd om een kopie van de vorige ingedrukte toets in een variabele te zetten:

Delphi:
1
2
3
4
5
6
[...]
KeyOld:=keymap;
Keymap:=ReadKey;
If KeyMap<>KeyOld then
    keys;
[...]


Maar, omdat je soms 2 keer dezelfde toets achter elkaar wilt aanslaan, zal dit niet werken.


Heeft iemand hier een oplossing voor? Ik heb zo'n gevoel dat 't doodsimpel is, maar toch kom ik er niet uit :X


Een tweede probleem is het aanslaan van akkoorden (meer dan één noot tegelijkertijd), dit lukt ook niet.

Hier heb ik al geprobeerd om port[$60] te gebruiken (toetsenbord), maar hier lukt het ook niet mee.

[ Voor 0% gewijzigd door een moderator op 06-09-2007 12:16 . Reden: even de highlighter erbij aangezet :P ]

IF IF = THEN THEN THEN = ELSE ELSE ELSE = IF;


Verwijderd

Volgens mij zijn er voor beide problemen geen makkelijke oplossingen. Maar het is alweer een aantal jaar geleden dat ik in TP heb geprogrammeerd, dus ik kan het verkeerd hebben.

Of wacht.. ik kan me vaag iets herinneren van een 3rd party dos library die allemaal extra procedures en functies had voor het toetsenbord, onder andere dus meerdere toetsen en die merkt als een toets weer losgelaten wil worden. Maarja, geen idee wat de naam daarvan is.

Met de standaard libraries van TP gaat het je niet lukken denk ik :)

Edit: overigens vind ik je een held dat je met pascal werkt. De nostalgie. Elf jaar geleden in leren programmeren, mijn eerste echte programmeer taal :P

[ Voor 12% gewijzigd door Verwijderd op 06-09-2007 00:04 ]


  • Icelus
  • Registratie: Januari 2004
  • Niet online
Misschien dat je met iets uit de SWAG-collectie kan, bijvoorbeeld door deze code als basis te nemen.

Developer Accused Of Unreadable Code Refuses To Comment


  • Vaan Banaan
  • Registratie: Februari 2001
  • Niet online

Vaan Banaan

Heeft ook Apache ontdekt

Het is al even geleden, dat ik met Pascal heb geprogrammeerd, maar ik doe toch een poging.
Volgens mij blijft de readkey wachten op een toetsaanslag.
Je hebt dus inderdaad het probleem, dat je niet weet of één toets 2x is aangeslagen, of dat het de repeterende tijddinges is.
Wat je volgens mij extra moet gebruiken is de Keypressed functie.
Dus na de readkey en het toontje een loop until not keypressed of iets dergelijks
[edit] Zoiets dus:
Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
13
Procedure Keys; 
Begin 
    KeyMap:=ReadKey;  {stop de waarde van ReadKey in variabele KeyMap); 
    Case KeyMap Of 
    '~' : Quit:=true;  {beëindig programma} 
    '2' : Begin 
        SetNoteOn(1,54,100); {Zet noot F sharp 4, midi 54, aan op kanaal 1 met velocity=100} 
        Writeln('F Sharp 4'); {Schrijf de gedrukte noot uit} 
        Repeat
        Until Not Keypressed;
          end; 
    end;
end;

Edit2: Dat lost je probleem van simultane toetsaanslagen niet op.
Op http://www.brain.uni-freiburg.de/~klaus/pascal/sources/ staat een stukje over allkeys.pas wat wel meerdere toesten tegelijk uit kan lezen.

[ Voor 46% gewijzigd door Vaan Banaan op 06-09-2007 13:01 ]

500 "The server made a boo boo"


  • link0007
  • Registratie: Augustus 2006
  • Niet online
Ok, ik ben er nog steeds niet uit.

Delphi:
1
2
3
Repeat
        Until Not Keypressed;
          end; 


Werkt niet.

Heel vaag, je zou denken dat het zou werken, maar hij werkt niet.

Hier de broncode en een executable (voor degenen zonder pascal):
Download MIDI_PIA.PAS

Download MIDI_PIANO.EXE


Sorry als het niet mag, maar lijkt me handig om volledige broncode te geven (en +- 300 regels code neerkwakken is ook zo irritant).


Kijk maar als je geïnteresseerd bent.

Problemen:
- simultane toonaanslag
- toon-lussen


edit:
Ok, nog wat meer gespeeld met allkeys.pas, maar daar heb je ook weinig aan.
Misschien als ik alle mogelijke akkoorden los zou programmeren..(ongeveer 42840 regels code, voor 3-noten polyfonie.. toch?;) )

[ Voor 16% gewijzigd door link0007 op 12-09-2007 20:14 ]

IF IF = THEN THEN THEN = ELSE ELSE ELSE = IF;


  • link0007
  • Registratie: Augustus 2006
  • Niet online
Iemand nog ideeën?

Wat doet deze code eigenlijk:
Delphi:
1
2
3
4
5
6
7
8
9
10
Procedure SetNoteOn(Channel,Note,velocity:Byte); Assembler;
ASM
    MOV   AL,[Channel]
    ADD   AL,90h
    Call  WriteGM
    MOV   AL,[Note]
    CALL  WriteGM
    MOV   AL,[velocity]
    CALL  WriteGM
End;


En kan ik er gewoon nog een noot+velocity tussen proppen?
zoals dit:
Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Procedure SetNoteOn(Channel,Note,velocity:Byte); Assembler;
ASM
    MOV   AL,[Channel]
    ADD   AL,90h
    Call  WriteGM
    MOV   AL,[Note]
    CALL  WriteGM
    MOV   AL,[velocity]
    CALL  WriteGM
    MOV   AL,[Note2]
    CALL  WriteGM
    MOV   AL,[velocity2]
    CALL  WriteGM
End;


Ik kan zelf geen assembly programmeren, maar het lukt me maar niet via pascal.. dus waarom niet de bron aanpakken?

IF IF = THEN THEN THEN = ELSE ELSE ELSE = IF;


  • Icelus
  • Registratie: Januari 2004
  • Niet online
link0007 schreef op zondag 16 september 2007 @ 22:31:
Iemand nog ideeën?

Wat doet deze code eigenlijk:
Delphi:
1
2
3
4
5
6
7
8
9
10
Procedure SetNoteOn(Channel,Note,velocity:Byte); Assembler;
ASM
    MOV   AL,[Channel]
    ADD   AL,90h
    Call  WriteGM
    MOV   AL,[Note]
    CALL  WriteGM
    MOV   AL,[velocity]
    CALL  WriteGM
End;
De code stuurt een MIDI ‘Note on’-commando naar een uitgangspoort toe.
Om een noot aan te zetten wordt er eerst een code van $90-$9f verzonden. De 9 geeft aan dat het om een note on gaat, de rest van de code (laagste 4 bits) geven het kanaal aan (0=1, 1=2, f=16).
Daarna volgt de noot die op dat kanaal aangezet moet worden en daarna de aanslag van de noot (127=hardst, 0=zachtst).
En kan ik er gewoon nog een noot+velocity tussen proppen?
zoals dit:
Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Procedure SetNoteOn(Channel,Note,velocity:Byte); Assembler;
ASM
    MOV   AL,[Channel]
    ADD   AL,90h
    Call  WriteGM
    MOV   AL,[Note]
    CALL  WriteGM
    MOV   AL,[velocity]
    CALL  WriteGM
    MOV   AL,[Note2]
    CALL  WriteGM
    MOV   AL,[velocity2]
    CALL  WriteGM
End;


Ik kan zelf geen assembly programmeren, maar het lukt me maar niet via pascal.. dus waarom niet de bron aanpakken?
Dat kan, maar kun je dan niet beter een (pascal) routine bouwen die een akkoord maakt door SetNoteOn een aantal maal aan te roepen?
Bijvoorbeeld een functie die een string die ‘halve noten’ bevat: '158' om een majeur te spelen, '148' voor mineur etc.

Developer Accused Of Unreadable Code Refuses To Comment

Pagina: 1