Entwickler-Ecke

Multimedia / Grafik - Ton erstellen (Dauer und Frequenz einstellen)


violinenspieler1000 - Sa 14.06.08 23:14
Titel: Ton erstellen (Dauer und Frequenz einstellen)
Hallo,


ich möchte mit Delphi einen Ton erzeugen, der in Dauer und Frequenz einstellbar sein soll.
Dazu habe ich MMSystem in uses eingebunden. Ich benutze die folgende Prozedur mit Aufruf:



Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
procedure Tform1.MakeSound(Frequency, Duration : integer);
{writes tone to memory and plays it}
var
  WaveFormatEx : TWaveFormatEx;
  MS           : TMemoryStream;
  i, TempInt,
  DataCount,
  RiffCount    : integer;
  SoundValue   : byte;
  w            : double; // omega ( 2 * pi * frequency)
const
  Mono       : Word = $0001;
  SampleRate : integer = 11025// 8000, 11025, 22050, or 44100
  RiffId     : string = 'RIFF';
  WaveId     : string = 'WAVE';
  FmtId      : string = 'fmt ';
  DataId     : string = 'data';
begin
  with WaveFormatEx do begin
    wFormatTag := WAVE_FORMAT_PCM;
    nChannels := Mono;
    nSamplesPerSec := SampleRate;
    wBitsPerSample := $0008;
    nAvgBytesPerSec := nSamplesPerSec * nBlockAlign;
    nBlockAlign := (nChannels * wBitsPerSample) div 8;
    cbSize := 0;
  end;
  MS := TMemoryStream.Create;
  with MS do begin
    {Calculate length of sound data and of file data}
    DataCount := (Duration *  SampleRate) div 1000;  // sound data
    RiffCount := Length(WaveId)
                 + Length(FmtId) + SizeOf(DWord)
                 + SizeOf(TWaveFormatEx)
                 + Length(DataId) + SizeOf(DWord)
                 + DataCount; // file data
    {write out the wave header}
    Write(RiffId[1], 4);                        // 'RIFF'
    Write(RiffCount, SizeOf(DWord));            // file data size
    Write(WaveId[1], Length(WaveId));           // 'WAVE'
    Write(FmtId[1], Length(FmtId));             // 'fmt '
    TempInt := SizeOf(TWaveFormatEx);
    Write(TempInt, SizeOf(DWord));              // TWaveFormat data size
    Write(WaveFormatEx, SizeOf(TWaveFormatEx)); // WaveFormatEx record
    Write(DataId[1], Length(DataId));           // 'data'
    Write(DataCount, SizeOf(DWord));            // sound data size
    {calculate and write out the tone signal}   // now the data values
    w := 2 * Pi * Frequency;  // omega
    for i := 0 to DataCount - 1 do begin
      // wt = w *i /SampleRate
      SoundValue := 127 + trunc(127 * sin(i * w / SampleRate));
      Write(SoundValue, SizeOf(Byte));
    end;
    // you could save the wave tone to file with :
    // MS.Seek(0, soFromBeginning);
    // MS.SaveToFile('C:\MyFile.wav');
    // then reload and play them without having to
    // construct them each time.
    {now play the sound}
    sndPlaySound(MS.Memory, SND_MEMORY or SND_SYNC);
    MS.Free;
  end;
end{Alan Lloyd}



procedure TForm1.Button1Click(Sender: TObject);
begin
MakeSound(100,60000);
end;



Leider funktioniert das nicht. Weiß jemand, wo der Fehler ist?

Maik

Moderiert von user profile iconAXMD: Delphi-Tags hinzugefügt


Marc. - Sa 14.06.08 23:17

Hi und :welcome: im Forum!
Was funktioniert nicht? Was spricht gegen die Verwendung von Windows.Beep(Frequ, Laenge); ?

€: Code-Tags -> [code] [/code] oder analog dazu Delphi-Tags -> [delphi] [/delphi]

Grüße,
Marc


violinenspieler1000 - Sa 14.06.08 23:48

Mit meiner Prozedur kommt einfach kein Ton.

Mit Windows.Beep(Frequ, Laenge); wird doch kein Ton über die Lautsprecher ausgegeben, oder?

Maik


Marc. - Sa 14.06.08 23:50

Bei mir schon. Du hättest es aber auch selbst ausprobieren können. ;)


violinenspieler1000 - Sa 14.06.08 23:58

Bei mir wird Windows.Beep(Frequ, Laenge); auf einem lautsprecher im computer ausgegeben (muss dasselbe ding sein, dass beim hochfahren einmal piep macht).
Kann man das irgendwie umstellen?


Maik


Marc. - So 15.06.08 18:57

Ich habe Deine Procedure MakeSound nun getestet. Resultat: Funktioniert einwandfrei.
Ich tippe mal stark darauf, dass deine Boxen nicht korrekt angeschlossen oder eingerichtet sind. ;)

Grüße,
Marc


hui1991 - So 15.06.08 19:58

Also ich hab das getestet mit Turbo Delphi Explorer auf Vista und es funktioniert nicht. Ich drück auf den Button und es passiert garnichts.


matox - Do 26.06.08 14:02

habe das heute mit XP getestet und nachdem ich den Procedure-Namen auf MakeSound gekürzt
habe gibt die Procedure alle Töne über die Lautsprecher aus.
procedure MakeSound(Frequency, Duration : integer);

Nachstehend die Tonleiter C2 - C3.

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
procedure TForm1.Button1Click(Sender: TObject);
     begin
  MakeSound(523,600); //C 2
  MakeSound(587,600); //D
  MakeSound(659,600); //E
  MakeSound(698,600); //F
  MakeSound(784,600); //G
  MakeSound(880,600); //H
  MakeSound(987,600); //A
  MakeSound(1046,600);//C 3
    end;


Gruß matox

Moderiert von user profile iconAXMD: Delphi-Tags hinzugefügt


Gelmo - Mo 22.04.13 11:22

Hallo zusammen!
Auf der Suche nach einer EINFACHEN Möglichkeit, mit Delphi einen Ton aus Frequenz- und Dauer-Angabe zu generieren, bin ich wiederholt auf diesen Beitrag gestoßen. Daher antworte ich jetzt darauf nach fast fünf Jahren. Ich habe den Code in eine eigene Unit kopiert und aus meinem Programm testweise aufgerufen. Ich erhalte aber keinen Ton.
Es passiert auch nichts, wenn ich die Zeilen 24 und 25 des Listings vertausche, was vermutlich nötig ist, da Zeile 24 auf die in Zeile 25 definierte Variable zugreift.
Kurz gefragt: Gibt es inzwischen in Delphi immer noch keine Möglichkeit, einfach einen Ton zu generieren. Ich verwende - als Hobby-Programmierer - zur Zeit Delphi XE Starter und werde mir auch keine teure Profi-Version mehr zulegen.
Freundliche Grüße von Gelmo


Delete - Mo 22.04.13 14:44

Im folgenden Code wird das Device Beep erzeugt bzw. genutzt -
es funktioniert auch unter WIN 7 - 64Bit



Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);

  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

type  BEEP_SET_PARAMETERS= record
      Frequency,Duration:cardinal;
      end;

const IOCTL_BEEP_SET=$10000;
      FNStr:array [0..9of char='\\.\huii'#0
      FN:PChar=@FNStr[0];
      DEVNAME : PChar=@FNStr[3];

var DEVPATH:array [0..MAX_PATH] of char;

implementation

{$R *.dfm}

function WindowsBeep(Freq,Duration:cardinal):longint;
var hBeep, bRET : cardinal;
    BSP : BEEP_SET_PARAMETERS;
    ODN : longbool;
begin
ODN:=false;
if QueryDosDevice(DEVNAME,DEVPATH,MAX_PATH)=0 then begin
   DefineDosDevice(DDD_RAW_TARGET_PATH,DEVNAME,'\Device\Beep');
   ODN:=true;
   end;
hBeep:=CreateFile (FN,GENERIC_READ or GENERIC_WRITE,0,nil,OPEN_EXISTING,0,0);
if hBeep=INVALID_HANDLE_VALUE then  begin Result:=E_FAIL; exit; end;
BSP.Frequency:= Freq;
BSP.Duration:= Duration;
DeviceIOControl(hBeep,IOCTL_BEEP_SET,@Freq,sizeof(BSP),nil,0,bRET,nil);
if ODN then DefineDosDevice(DDD_REMOVE_DEFINITION,DEVNAME,nil);
Sleep(BSP.Duration);
CloseHandle(hBeep);
Result:=S_OK;
end;
//-----------------------------------------------------------------------------
Procedure DLAY;
BEGIN
  sleep(0);
END;

procedure TForm1.FormCreate(Sender: TObject);
begin
WindowsBeep(3000,150);
end;


procedure TForm1.Button1Click(Sender: TObject);
begin
WindowsBeep(1000,150);
end;

procedure TForm1.Button2Click(Sender: TObject);
var i:Integer;
begin
  for I := 1 to 10 do BEGIN
    WindowsBeep(I*500,100);
    DLAY;
  END;
end;


bummi - Mo 22.04.13 14:54

vielleicht ist das ja was für Dich
http://stackoverflow.com/questions/16125462/how-to-create-sound-notes-in-delphi


Gelmo - Di 23.04.13 11:50

Hallo!
Habe das Listing in ein Testprogramm mit zwei Formularen eingebaut. Im 1. werden Frequenz und Dauer bestimmt, im 2. befindet sich das Listing oben, natürlich angepasst auf Form2. Übergebe dann an WindowsBeep die Parameter. Dabei wird kein Ton ausgegeben. Ich vermute, dass die Werte für die im Code verwendeten Variablen durch Windows ermittelt werden. Oder müsste ich eine oder mehrere davon neben Freuquenz und Dauer selbst übergeben?
Übrigens Windows.beep(...) funktioniert, aber wer will schon "Beep"-Musik hören?
Dennoch vielen Dank, Gelmo


Delete - Di 23.04.13 18:09

Wenn Du guten Sound haben willst, musst Du MIDI nehmen.

Da kann man unter 127 Instrumenten auswählen, die Lautstärke einstellen für L+R u.a.

In WINDOWS ist als Device Microsoft GS Wavetable Synth vorhanden.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198:
199:
200:
201:
202:
203:
204:
205:
206:
207:
208:
209:
210:
211:
212:
213:
214:
215:
216:
217:
218:
219:
220:
221:
222:
223:
224:
225:
226:
227:
228:
229:
230:
231:
232:
233:
234:
235:
236:
237:
238:
239:
240:
241:
242:
243:
244:
245:
246:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, MMSystem, ComCtrls;

type
  TMIDIInstrument = (midiAcousticGrandPiano, midiBrightAcousticPiano,
                     midiElectricGrandPiano, midiHonkyTonkPiano,
                     midiRhodesPiano, midiChorusedPiano, midiHarpsichord,
                     midiClavinet, midiCelesta, midiGlockenspiel,
                     midiMusicBox, midiVibraphone, midiMarimba, midiXylophone,
                     midiTubularBells, midiDulcimer, midiHammondOrgan,
                     midiPercussiveOrgan, midiRockOrgan, midiChurchOrgan,
                     midiReedOrgan, midiAccordion, midiHarmonica,
                     midiTangoAccordion, midiAcousticGuitarNylon,
                     midiAcousticGuitarSteel, midiElectricGuitarJazz,
                     midiElectricGuitarClean, midiElectricGuitarMuted,
                     midiOverdrivenGuitar, midiDistortionGuitar,
                     midiGuitarHarmonics, midiAcousticBass, midiElectricBassFinger,
                     midiElectricBassPick, midiFretlessBass, midiSlapBass1,
                     midiSlapBass2, midiSynthBass1, midiSynthBass2, midiViolin,
                     midiViola, midiCello, midiContrabass, midiTremoloStrings,
                     midiPizzicatoStrings, midiOrchestralHarp, midiTimpani,
                     midiStringEnsemble1, midiStringEnsemble2, midiSynthStrings1,
                     midiSynthStrings2, midiChoirAahs, midiVoiceOohs,
                     midiSynthVoice, midiOrchestraHit, midiTrumpet, midiTrombone,
                     midiTuba, midiMutedTrumpet, midiFrenchHorn, midiBrassSection,
                     midiSynthBrass1, midiSynthBrass2, midiSopranoSax, midiAltoSax,
                     midiTenorSax, midiBaritoneSax, midiOboe, midiEnglishHorn,
                     midiBassoon, midiClarinet, midiPiccolo, midiFlute,
                     midiRecorder, midiPanFlute, midiBottleBlow, midiShakuhachi,
                     midiWhistle, midiOcarina, midiLead1Square,
                     midiLead2Sawtooth, midiLead3CalliopeLead, midiLead4ChiffLead,
                     midiLead5Charang, midiLead6Voice, midiLead7Fifths,
                     midiLead8BrassLead, midiPad1NewAge, midiPad2Warm,
                     midiPad3Polysynth, midiPad4Choir, midiPad5Bowed,
                     midiPad6Metallic, midiPad7Halo, midiPad8Sweep, midiEmpty0,
                     midiEmpty1, midiEmpty2, midiEmpty3, midiEmpty4, midiEmpty5,
                     midiEmpty6, midiEmpty7, midiEmpty8, midiEmpty9, midiEmpty10,
                     midiEmpty11, midiEmpty12, midiEmpty13, midiEmpty14,
                     midiEmpty15, midiEmpty16, midiEmpty17, midiEmpty18,
                     midiEmpty19, midiEmpty20, midiEmpty21, midiEmpty22,
                     midiEmpty23, midiGuitarFretNoise, midiBreathNoise,
                     midiSeashore, midiBirdTweet, midiTelephoneRing,
                     midiHelicopter, midiApplause, midiGunshot);



type
  TForm1 = class(TForm)
    Button10: TButton;
    Button33: TButton;
    Button41: TButton;
    Button42: TButton;
    Button43: TButton;
    Button44: TButton;
    TrackBar1: TTrackBar;
    ComboBox1: TComboBox;
    procedure Button10Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Button33Click(Sender: TObject);
    procedure Button41Click(Sender: TObject);
    procedure Button42Click(Sender: TObject);
    procedure Button43Click(Sender: TObject);

  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
    procedure GetMidiVolume(var volLe, volRi: Word);
    procedure SetMidiVolume(var volLe, volRi: Word);
  end;

var
  Form1: TForm1;
  mo: HMIDIOUT;
  volLe, volRi: Word;

const
  MIDI_NOTE_ON = $90;
  MIDI_NOTE_OFF = $80;
  MIDI_CHANGE_INSTRUMENT = $C0;

  MAX_VOLUME = 65535;
  HALF_VOLUME = 32768;
  MIN_VOLUME = 0;
  FADE_SPEED = 64;

implementation

{$R *.dfm}
//-----------------------------------------------------------------MIDI
function MIDIEncodeMessage(Msg, Param1, Param2: byte): integer;
begin
  result := Msg + (Param1 shl 8) + (Param2 shl 16);
end;

procedure NoteOn(NewNote, NewIntensity: byte);
begin
  midiOutShortMsg(mo, MIDIEncodeMessage(MIDI_NOTE_ON, NewNote, NewIntensity));
end;

procedure NoteOff(NewNote, NewIntensity: byte);
begin
  midiOutShortMsg(mo, MIDIEncodeMessage(MIDI_NOTE_OFF, NewNote, NewIntensity));
end;

procedure SetInstrument(NewInstrument: byte);
begin
  midiOutShortMsg(mo, MIDIEncodeMessage(MIDI_CHANGE_INSTRUMENT, NewInstrument, 0));
end;

procedure SetCurrentInstrument2(NewInstrument: Integer);
begin
  midiOutShortMsg(mo, MIDIEncodeMessage(MIDI_CHANGE_INSTRUMENT, NewInstrument, 0));
end;

procedure SetCurrentInstrument(CurrentInstrument: TMIDIInstrument);
begin
  midiOutShortMsg(mo, MIDIEncodeMessage(MIDI_CHANGE_INSTRUMENT, ord(CurrentInstrument), 0));
end;

procedure InitMIDI;
begin
  midiOutOpen(@mo, 000, CALLBACK_NULL);
  midiOutShortMsg(mo, MIDIEncodeMessage(MIDI_CHANGE_INSTRUMENT, 00));
end;

procedure SetPlaybackVolume(PlaybackVolume: cardinal); // 0 - 65535
begin
  midiOutSetVolume(mo, PlaybackVolume);
  Form1.TrackBar1.Position:= PlaybackVolume;
  Form1.Trackbar1.SelEnd:= Form1.TrackBar1.Position;
end;

procedure TForm1.GetMidiVolume(var volLe, volRi: Word);
var vol: DWORD;
begin
 volLe := 0;
 volRi := 0;
 midiOutGetVolume(0, @vol);
 volLe := vol and $FFFF;
 volRi := vol shr 16;
 //Weiterbearbeitung...
end;

procedure TForm1.SetMidiVolume(var volLe, volRi: Word);
var vol: DWORD;
begin
 vol := volLe + volRi shl 16;
 midiOutSetVolume(0, vol);
end;
//-----------------------------------------------------------------MIDI - Ende
procedure TForm1.Button10Click(Sender: TObject);
begin
NoteOn(50127);
Sleep(500);
NoteOff(50127);
SetInstrument(60);
NoteOn(60127);
Sleep(500);
NoteOff(60127);
SetInstrument(80);
NoteOn(70127);
Sleep(500);
NoteOff(70127);
SetInstrument(90);
NoteOn(80127);
Sleep(500);
NoteOff(80127);
SetInstrument(100);
NoteOn(90127);
Sleep(500);
NoteOff(90127);
SetInstrument(12);
NoteOn(40127);
Sleep(1000);
NoteOff(40127);
end;

procedure TForm1.Button33Click(Sender: TObject);
begin
  SetCurrentInstrument(midiHarmonica);
  SetPlaybackVolume(65535);
  NoteOn(50127);
  sleep(200);
  NoteOn(60127);
  sleep(200);
  NoteOn(70127);
  sleep(200);
  NoteOff(70127);
  NoteOff(60127);
  NoteOff(50127);
  SetCurrentInstrument(midiAcousticGrandPiano);
  SetPlaybackVolume(32000);
  NoteOn(70127);
  NoteOn(80127);
  sleep(1000);
  NoteOff(80127);
  NoteOff(70127);
  SetCurrentInstrument(midiApplause);
  SetPlaybackVolume(65535);
  NoteOn(64127);
  sleep(2000);
  NoteOff(64127);
end;

procedure TForm1.Button41Click(Sender: TObject);
begin
  SetPlaybackVolume(MAX_VOLUME);
end;

procedure TForm1.Button42Click(Sender: TObject);
begin
SetPlaybackVolume(HALF_VOLUME);
end;

procedure TForm1.Button43Click(Sender: TObject);
begin
SetPlaybackVolume(0);
end;

procedure GetMidiOutDevices2;
var
  dev: Integer;
  caps: TMidiOutCaps;
begin
  Form1.ComboBox1.Clear;
  for dev := 0 to midiOutGetNumDevs - 1 do
  begin
    midiOutGetDevCaps(dev, @caps, sizeof(TMidiOutCaps));
    Form1.ComboBox1.Items.Add(caps.szPname);
  end;
  Form1.ComboBox1.ItemIndex := 0//primäre Soundkarte
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
GetMidiOutDevices2;
InitMIDI;
end;

end.


FinnO - Di 23.04.13 18:19

user profile iconhathor hat folgendes geschrieben Zum zitierten Posting springen:
Wenn Du guten Sound haben willst, musst Du MIDI nehmen.

Da kann man unter 127 Instrumenten auswählen, die Lautstärke einstellen für L+R u.a.


Moin,

also irgendwo hört der Spaß dann auch mal auf. MIDI ist in erster Linie ein Protokoll für elektronische Eingabegeräte, z.B. Keyboards. Wenn er guten Sound haben will, muss er sich in Softwaresynthese von Sounds einarbeiten. Und wenn er den Sound dann auch noch selbst ausgeben will, dann auch in Soundausgabe, Bufferhandling etc. Das kann man mit WMI machen, ist aber wirklich nicht leicht. user profile iconMartok kann das ;). Die Sache geht bestimmt auch mit der bass.dll oder sowas. Aber davon habe ich wirklich keine Ahnung.

Gruß


Gelmo - Fr 03.05.13 15:12

Hallo zusammen!
War einige Tage im Urlaub und kann mich erst jetzt wieder hier melden. Den Beitrag von Hathor finde ich durchaus nicht lächerlich. Bisher habe ich mit dem Code noch keinen Ton erzeugt. Habe diesen in ein Testprogramm eingefügt mit den entsprechenden Komponenten. Beim Kompilieren wird kein Fehler mehr angezeigt, aber es kommt auch kein Ton. Vielleicht klappt es ja, wenn ich noch etwas experimentiere.
Mit Softwaresynthese oder Soundausgabe möchte ich mich bei meinen Vorkenntnissen nicht befassen. Dann stellt Delphi eben auf akustischem Gebiet im Gegensatz zu den graphischen Komponenten keine Objekte zur Verfügung.
Nochmals vielen Dank, mit freundlichen Grüßen
Gelmo


Delete - Fr 03.05.13 17:25

Welches BS?
Vielleicht ist die Software für den Soundchip nicht vollständig installiert.
Name des Soundchips?
Wird beim Test-Programm in der Combobox nach dem Start gleich etwas angezeigt (Microsoft GS Wavetable Synth)?


Mathematiker - Fr 03.05.13 23:24

Hallo hathor,
user profile iconhathor hat folgendes geschrieben Zum zitierten Posting springen:
Wenn Du guten Sound haben willst, musst Du MIDI nehmen.

Ich habe Dein Beispiel ausprobiert und finde es ziemlich gut.
Meine eigenen Versuche, vernünftige Töne zu erzeugen, gingen aber voll in die Hose.

Irgendwie bin ich noch nicht dahinter gekommen, was bei

Delphi-Quelltext
1:
2:
3:
4:
procedure NoteOn(NewNote, NewIntensity: byte);
begin
  midiOutShortMsg(mo, MIDIEncodeMessage(MIDI_NOTE_ON, NewNote, NewIntensity));
end;

der Parameter NewNote beschreibt. Die Frequenz kann es nicht sein, aber welcher Wert ist das dann?
Sind die Töne durchnumeriert? Aber wie?

Beste Grüße
Mathematiker


FinnO - Fr 03.05.13 23:26

Ohne Kenntnis behaupte ich, dass die Töne gemäß dem MIDI [http://en.wikipedia.org/wiki/MIDI]-Standard von 0-127 durchnummeriert sind.#

Du kannst natürlich auch umrechnen:


Quelltext
1:
 fm  =  2^((m−69)/12) * (440 Hz)                    


Mit der Annahme, dass 440Hz der Kammerton ist.


Mathematiker - Fr 03.05.13 23:32

Hallo,
user profile iconFinnO hat folgendes geschrieben Zum zitierten Posting springen:
Du kannst natürlich auch umrechnen:

Quelltext
1:
 fm  =  2^((m−69)/12) * (440 Hz)                    

Danke. Das ist genau das, was ich suche.

Beste Grüße
Mathematiker


Martok - Sa 04.05.13 00:11

Moin!

Und wie immer gibt es ein DGL-Tutorial dazu: Software-Synthesizer [http://wiki.delphigl.com/index.php/Tutorial_Software-Synthesizer].

Nun ist das durchaus nicht der Weisheit letzter Schluss, das was user profile iconFinnO weiter oben meint hat mich auch ein paar Wochen Forschungsarbeit gekostet (und das war nicht genug um's komplett zum Funktionieren zu kriegen, gibt ein paar Threads dazu hier). Und es wird nicht unbedingt dadurch einfacher dass Microsoft in jeder Windowsversion ein neues Soundsystem einführt. Deswegen dürfte vermutlich auch die MMSystem-Version nicht mehr funktionieren, auch wenn der Code an sich (auf den ersten Blick, der kommt mir "von früher" bekannt vor) nicht kaputt ist.

Im Endeffekt gehts aber immer nur um eins: irgendwo schreibst du das Signal hin und lässt es auf die Soundkarte schieben.

"Jemand" sollte mal eine Bibliothek für sowas schreiben. Problem: je nach Anforderung kann man durchaus komplett andere Ansätze wählen. Fmod mag ich nicht so (vor allem wegen der aktuellen undurchsichtigen Lizenz), Bass geht wunderbar aber schwierig mit Threads, die MMSystem-waveOut-API gibt's immer noch (wenn sie mal funktioniert) und direkt per OpenAL o.ä. könnte man auch noch ran.


FinnO - Sa 04.05.13 00:24

Moin,

ich würde tatsächlich bei solchen Anwendungen jedem ASIO [http://www.steinberg.net/de/company/developer.html] nahelegen. Nicht, dass ich über die Maßen Erfahrung gesammelt hätte, aber unter Windows ist es nun mal Industriestandard und ist dank Asio4All [http://www.asio4all.com/] auch mit nicht-High-End Soundkarten kompatibel. Wem Buffermanagement zu anstrengend ist und nicht unbedingt auf eine Standalone-Anwendung angewiesen ist, der sollte meiner Meinung nach ein VST-Plugin implementieren, das ist sogar nichtmal besonders schwierig, gerade wo Delphi recht einfach DLLs unterstützt.

Gruß


Mathematiker - So 05.05.13 15:10

Hallo,
obwohl ich von Musik so viel Ahnung habe, wie "die Kuh von der Botanik der Pflanzen, die sie mit Wohlbehagen frisst" ("geklautes" Einstein-Zitat), musste ich es sofort ausprobieren.

Das angehängte Programm wird allen, die am Computer Musik machen, das blanke Grauen in die Gliedmaßen treiben. Ich bin aber zufrieden. :P
Im Programm werden einzelne Töne (Frequenz, Tonleiter, ...) über das weiter oben beschriebene MIDI ausgegeben.
Als Mathematiker habe ich natürlich sofort PI und e in Töne transformiert. Jeweils 50 werden hintereinander abgespielt und es klingt grauenvoll schön. :wink:

Beste Grüße
Mathematiker

Rev 1: Das Programm zeigt jetzt eine Klaviertastatur, auf der man mit Mausklick Töne abspielen kann.

Wichtiger Hinweis: Das Programm und seine weiteren Versionen werde ich in einen Extra-Thread in die Sparte Open-Source übertragen.
siehe http://www.entwickler-ecke.de/viewtopic.php?t=111517


Delete - So 05.05.13 18:28

Da kann ich auch noch etwas beitragen:

CLAVIER ARRANGEUR MIDI VIRTUEL

http://www.delphifr.com/code.aspx?ID=52564


Mathematiker - So 05.05.13 18:59

Hallo hathor,
user profile iconhathor hat folgendes geschrieben Zum zitierten Posting springen:
Da kann ich auch noch etwas beitragen:
CLAVIER ARRANGEUR MIDI VIRTUEL

Danke für den Hinweis. Soweit ich es aus den Dateien erkennen kann, ist das Programm professionell.
Mein Versuch ist dagegen lächerlich.

Leider kann ich es mit meinem Delphi 5 nicht compilieren. Zum einen fehlen mir Komponenten, zum anderen wirft mein Delphi weitere Objekte beim Öffnen 'raus, da irgendwelche Eigenschaften nicht existieren.
Kannst Du es compilieren?

Beste Grüße
Mathematiker


Delete - So 05.05.13 19:19

EXE oben hinzugefügt: Ein fehlerhafter Listenindex muss noch gesucht und korrigiert werden...
Kompiliert mit DELPHI 2009.

Folgendes hilft "auf die Schnelle":
// Application.CreateForm(TFormPrefer, FormPrefer);

Neue EXE ist oben.


Mathematiker - So 05.05.13 20:09

Hallo,
user profile iconhathor hat folgendes geschrieben Zum zitierten Posting springen:
Kompiliert mit DELPHI 2009.

Nach den ersten Tests kann ich zum "Klavier" nur sagen: hervorragend.

Insbesondere finde ich die Idee der Klaviertastatur interessant und außerdem, dass man hier zwei und mehr Töne gleichzeitig spielen kann. Ich habe noch viel zu lernen. Zumindest verstehe ich jetzt, wieso bestimmte Zahlen den Tönen bei MIDI zugeordnet werden.
Wenn Du nichts dagegen hast, würde ich das Panel "Piano" in mein bescheidenes Programm kopieren. Das Zusammenstellen der Klaviertastatur aus Shapes könnte ich mir so sparen. :wink:

Beste Grüße
Mathematiker


Delete - So 05.05.13 20:15

Das Programm ist nicht von mir!
Mach trotzdem damit, was Du willst...

SCHÖNEN ABEND!


Mathematiker - So 05.05.13 21:50

Hallo,
beeindruckt von dem Programm CLAVIER ARRANGEUR MIDI VIRTUEL (http://www.delphifr.com/code.aspx?ID=52564), das user profile iconhathor vorgestellt hat, habe ich in meinem Versuch nun auch eine Klaviertastatur aufgenommen (Rev 1).
Ich gestehe, dass ich das Panel mit den "Tasten" aus dem Programm entnommen habe :oops: , mehr aber nicht. :angel:

Man kann jetzt mit Mausklick auf die Klaviertasten Töne abspielen. Andererseits werden beim Abspielen der anderen Möglichkeiten, die zu drückenden Tasten angezeigt.

Mehr wird wohl nicht mehr werden. Dafür fehlen mir die musikalischen Kenntnisse und Fähigkeiten.

Beste Grüße
Mathematiker