@@ -10,7 +10,8 @@ uses |
| 10 |
about_hugetracker, TrackerGrid, lclintf, lmessages, Buttons, Grids, DBCtrls, |
10 |
about_hugetracker, TrackerGrid, lclintf, lmessages, Buttons, Grids, DBCtrls, |
| 11 |
HugeDatatypes, LCLType, Clipbrd, RackCtls, Codegen, SymParser, options, |
11 |
HugeDatatypes, LCLType, Clipbrd, RackCtls, Codegen, SymParser, options, |
| 12 |
bgrabitmap, effecteditor, RenderToWave, modimport, mainloop, strutils, |
12 |
bgrabitmap, effecteditor, RenderToWave, modimport, mainloop, strutils, |
| 13 |
Types, Keymap, hUGESettings, vgm, TBMImport, FurImport, InstrumentPreview, findreplace; |
13 |
Types, Keymap, hUGESettings, vgm, TBMImport, FurImport, InstrumentPreview, findreplace, |
|
|
14 |
MidiInput; |
| 14 |
|
15 |
|
| 15 |
// TODO: Move to config file? |
16 |
// TODO: Move to config file? |
| 16 |
const |
17 |
const |
@@ -541,9 +542,19 @@ type |
| 541 |
procedure PreviewInstrument(Note: Integer; Instr: TInstrument; SquareOnCh2: Boolean = False); overload; |
542 |
procedure PreviewInstrument(Note: Integer; Instr: TInstrument; SquareOnCh2: Boolean = False); overload; |
| 542 |
procedure PreviewNote(Note: Integer); |
543 |
procedure PreviewNote(Note: Integer); |
| 543 |
procedure Panic; |
544 |
procedure Panic; |
|
|
545 |
|
|
|
546 |
procedure OnMidiNoteOn(Sender: TObject; Note, Velocity: Integer); |
|
|
547 |
procedure OnMidiNoteOff(Sender: TObject; Note, Velocity: Integer); |
|
|
548 |
|
|
|
549 |
// Shared between the computer-keyboard preview path (FormKeyDown) and |
|
|
550 |
// MIDI note-on. Re-points InstrumentComboBox at the current channel's |
|
|
551 |
// bank, then previews the note. Returns False if the note shouldn't |
|
|
552 |
// actually be played (no instrument selected, unknown note, etc.). |
|
|
553 |
function PreviewForNoteEntry(Note: Integer): Boolean; |
| 544 |
public |
554 |
public |
| 545 |
procedure OnTrackerGridResize(Sender: TObject); |
555 |
procedure OnTrackerGridResize(Sender: TObject); |
| 546 |
procedure OnTrackerGridCursorOutOfBounds; |
556 |
procedure OnTrackerGridCursorOutOfBounds; |
|
|
557 |
procedure ApplyMidiSettings; |
| 547 |
end; |
558 |
end; |
| 548 |
|
559 |
|
| 549 |
var |
560 |
var |
@@ -928,6 +939,53 @@ begin |
| 928 |
UnlockPlayback; |
939 |
UnlockPlayback; |
| 929 |
end; |
940 |
end; |
| 930 |
|
941 |
|
|
|
942 |
procedure TfrmTracker.OnMidiNoteOn(Sender: TObject; Note, Velocity: Integer); |
|
|
943 |
begin |
|
|
944 |
if LoadingFile or Playing then Exit; |
|
|
945 |
if (Note < LOWEST_NOTE) or (Note > HIGHEST_NOTE) then Exit; |
|
|
946 |
|
|
|
947 |
// MIDI input mirrors computer-keyboard behaviour: re-aim the instrument |
|
|
948 |
// combo box at the current channel's bank and preview through that |
|
|
949 |
// instrument, then commit the note into the active cell. PreviewingInstrument |
|
|
950 |
// is tracked so the matching Note Off can silence the preview, the same |
|
|
951 |
// way FormKeyUp handles a released computer key. |
|
|
952 |
if TrackerSettings.PreviewWhenPlacing |
|
|
953 |
and (ActiveControl = TrackerGrid) |
|
|
954 |
and PreviewForNoteEntry(Note) then |
|
|
955 |
PreviewingInstrument := Note |
|
|
956 |
else |
|
|
957 |
PreviewNote(Note); |
|
|
958 |
|
|
|
959 |
if (ActiveControl = TrackerGrid) and (TrackerGrid.Cursor.SelectedPart = cpNote) then |
|
|
960 |
TrackerGrid.InputNoteValue(Note); |
|
|
961 |
end; |
|
|
962 |
|
|
|
963 |
procedure TfrmTracker.OnMidiNoteOff(Sender: TObject; Note, Velocity: Integer); |
|
|
964 |
begin |
|
|
965 |
if PreviewingInstrument <> -1 then begin |
|
|
966 |
PreviewingInstrument := -1; |
|
|
967 |
Panic; |
|
|
968 |
end; |
|
|
969 |
end; |
|
|
970 |
|
|
|
971 |
procedure TfrmTracker.ApplyMidiSettings; |
|
|
972 |
begin |
|
|
973 |
if not TrackerSettings.MIDIInputEnabled then begin |
|
|
974 |
if Midi.IsOpen then Midi.CloseDevice; |
|
|
975 |
Exit; |
|
|
976 |
end; |
|
|
977 |
|
|
|
978 |
if not Midi.Available then Exit; |
|
|
979 |
|
|
|
980 |
Midi.OnNoteOn := @OnMidiNoteOn; |
|
|
981 |
Midi.OnNoteOff := @OnMidiNoteOff; |
|
|
982 |
|
|
|
983 |
if TrackerSettings.MIDIInputDevice = '' then Exit; |
|
|
984 |
|
|
|
985 |
if Midi.DeviceName <> TrackerSettings.MIDIInputDevice then |
|
|
986 |
Midi.OpenDevice(TrackerSettings.MIDIInputDevice); |
|
|
987 |
end; |
|
|
988 |
|
| 931 |
procedure TfrmTracker.OnTrackerGridResize(Sender: TObject); |
989 |
procedure TfrmTracker.OnTrackerGridResize(Sender: TObject); |
| 932 |
var |
990 |
var |
| 933 |
I: Integer; |
991 |
I: Integer; |
@@ -1553,13 +1611,42 @@ begin |
| 1553 |
LoadSong(ParamStr(1)) |
1611 |
LoadSong(ParamStr(1)) |
| 1554 |
else |
1612 |
else |
| 1555 |
UpdateUIAfterLoad; |
1613 |
UpdateUIAfterLoad; |
|
|
1614 |
|
|
|
1615 |
ApplyMidiSettings; |
|
|
1616 |
end; |
|
|
1617 |
|
|
|
1618 |
function TfrmTracker.PreviewForNoteEntry(Note: Integer): Boolean; |
|
|
1619 |
var |
|
|
1620 |
Freq: Integer; |
|
|
1621 |
begin |
|
|
1622 |
Result := False; |
|
|
1623 |
if TrackerGrid.Cursor.SelectedPart <> cpNote then Exit; |
|
|
1624 |
if InstrumentComboBox.ItemIndex <= 0 then Exit; |
|
|
1625 |
if not NotesToFreqs.TryGetData(Note, Freq) then Exit; |
|
|
1626 |
|
|
|
1627 |
// Re-map the current combo-box selection into the bank that matches the |
|
|
1628 |
// channel the cursor is on (square / wave / noise), then push that back |
|
|
1629 |
// onto TrackerGrid.SelectedInstrument so the note that gets committed |
|
|
1630 |
// into the cell picks up the correct instrument number. |
|
|
1631 |
case TrackerGrid.Cursor.X of |
|
|
1632 |
0..1: InstrumentComboBox.ItemIndex := UnmodInst(itSquare, TrackerGrid.SelectedInstrument); |
|
|
1633 |
2: InstrumentComboBox.ItemIndex := UnmodInst(itWave, TrackerGrid.SelectedInstrument); |
|
|
1634 |
3: InstrumentComboBox.ItemIndex := UnmodInst(itNoise, TrackerGrid.SelectedInstrument); |
|
|
1635 |
end; |
|
|
1636 |
TrackerGrid.SelectedInstrument := ModInst(InstrumentComboBox.ItemIndex); |
|
|
1637 |
|
|
|
1638 |
if TrackerGrid.Cursor.X = 1 then |
|
|
1639 |
PreviewInstrument(Note, InstrumentComboBox.ItemIndex, True) |
|
|
1640 |
else |
|
|
1641 |
PreviewInstrument(Note, InstrumentComboBox.ItemIndex, False); |
|
|
1642 |
|
|
|
1643 |
Result := True; |
| 1556 |
end; |
1644 |
end; |
| 1557 |
|
1645 |
|
| 1558 |
procedure TfrmTracker.FormKeyDown(Sender: TObject; var Key: Word; |
1646 |
procedure TfrmTracker.FormKeyDown(Sender: TObject; var Key: Word; |
| 1559 |
Shift: TShiftState); |
1647 |
Shift: TShiftState); |
| 1560 |
var |
1648 |
var |
| 1561 |
Note: Integer; |
1649 |
Note: Integer; |
| 1562 |
Freq: Integer; |
|
|
| 1563 |
begin |
1650 |
begin |
| 1564 |
// Guard conditions |
1651 |
// Guard conditions |
| 1565 |
if TrackerGrid.Cursor.SelectedPart <> cpNote then Exit; |
1652 |
if TrackerGrid.Cursor.SelectedPart <> cpNote then Exit; |
@@ -1574,23 +1661,10 @@ begin |
| 1574 |
PreviewingInstrument := -1; |
1661 |
PreviewingInstrument := -1; |
| 1575 |
|
1662 |
|
| 1576 |
if (PreviewingInstrument > -1) or |
1663 |
if (PreviewingInstrument > -1) or |
| 1577 |
(not (ActiveControl = TrackerGrid)) or |
1664 |
(not (ActiveControl = TrackerGrid)) |
| 1578 |
(InstrumentComboBox.ItemIndex <= 0) |
|
|
| 1579 |
then exit; |
1665 |
then exit; |
| 1580 |
|
1666 |
|
| 1581 |
if not NotesToFreqs.TryGetData(Note, Freq) then Exit; |
1667 |
if not PreviewForNoteEntry(Note) then Exit; |
| 1582 |
|
|
|
| 1583 |
case TrackerGrid.Cursor.X of |
|
|
| 1584 |
0..1: InstrumentComboBox.ItemIndex := UnmodInst(itSquare, TrackerGrid.SelectedInstrument); |
|
|
| 1585 |
2: InstrumentComboBox.ItemIndex := UnmodInst(itWave, TrackerGrid.SelectedInstrument); |
|
|
| 1586 |
3: InstrumentComboBox.ItemIndex := UnmodInst(itNoise, TrackerGrid.SelectedInstrument); |
|
|
| 1587 |
end; |
|
|
| 1588 |
TrackerGrid.SelectedInstrument := ModInst(InstrumentComboBox.ItemIndex); |
|
|
| 1589 |
|
|
|
| 1590 |
if TrackerGrid.Cursor.X = 1 then |
|
|
| 1591 |
PreviewInstrument(Note, InstrumentComboBox.ItemIndex, True) |
|
|
| 1592 |
else |
|
|
| 1593 |
PreviewInstrument(Note, InstrumentComboBox.ItemIndex, False); |
|
|
| 1594 |
|
1668 |
|
| 1595 |
PreviewingInstrument := Note; |
1669 |
PreviewingInstrument := Note; |
| 1596 |
PreviewingWithKey := Key; |
1670 |
PreviewingWithKey := Key; |