Merge lp:~mixxxdevelopers/mixxx/features_portmidi into lp:~mixxxdevelopers/mixxx/trunk

Proposed by Sean M. Pappalardo
Status: Superseded
Proposed branch: lp:~mixxxdevelopers/mixxx/features_portmidi
Merge into: lp:~mixxxdevelopers/mixxx/trunk
Prerequisite: lp:mixxx/1.7
Diff against target: 8460 lines
To merge this branch: bzr merge lp:~mixxxdevelopers/mixxx/features_portmidi
Reviewer Review Type Date Requested Status
Mixxx Development Team Pending
Review via email: mp+14577@code.launchpad.net

This proposal has been superseded by a proposal from 2009-11-11.

To post a comment you must log in.
Revision history for this message
Sean M. Pappalardo (pegasus-renegadetech) wrote :

Mutliple MIDI device support has been working for a few weeks now with limited testing by myself and Phillip. The essential user-facing GUI changes are now complete, so this is ready to be considered for merging to trunk in time for v1.8.

2519. By Sean M. Pappalardo

Removed unneeded include

Revision history for this message
RJ Skerry-Ryan (rryan) wrote :

Pegasus wrote:
> Pegasus has proposed merging lp:~mixxxdevelopers/mixxx/features_portmidi into lp:mixxx with lp:mixxx/1.7 as a prerequisite.
>
> Requested reviews:
> Mixxx Development Team (mixxxdevelopers)
>
>
> Mutliple MIDI device support has been working for a few weeks now with limited testing by myself and Phillip. The essential user-facing GUI changes are now complete, so this is ready to be considered for merging to trunk in time for v1.8.
>
I think you didn't quite finish merging this or something because there
are some merge conflict markers scattered across this diff.

Revision history for this message
Sean M. Pappalardo (pegasus-renegadetech) wrote :

I was wondering about those. But they're not in the PM branch or 1.7. I guess they're a result of my specifying that merging the 1.7 branch to trunk is a prerequisite for merging this one?? (I guess that's not strictly true since this branch is based on 1.7 and the single merge would net both branches to trunk, effectively, no?)

Revision history for this message
Phillip Whelan (pwhelan) wrote :

You should probably rebase off trunk since no new features are being
merged into 1.7.

Revision history for this message
RJ Skerry-Ryan (rryan) wrote :

pwhelan wrote:
> You should probably rebase off trunk since no new features are being
> merged into 1.7.
>
Yea I agree -- you should rebase this branch to trunk so that the diff
we are looking at is exactly what will be added to trunk if the merge is
approved.

2520. By RJ Skerry-Ryan

Rebase merge of features_portmidi from the 1.7.x series to trunk.

2521. By Sean M. Pappalardo

Fixed a couple trunk merge issues

2522. By RJ Skerry-Ryan

Since the MidiMapping lock is now recursive, make buildDomElement() just relock it instead of asserting it is held.

2523. By Albert Santoni

* Select the autopaired output device in the MIDI bindings dialog's combobox, but grey it out.
* Removed some obsolete "correspondingOutputDevice" functions. We deprecated that in favour of the aggregating MidiDevice approach.
* Cleaned up some other obsolete stuff.

2524. By Albert Santoni

Only look for porttime header because it's symbols live inside the portmidi shared lib

2525. By Albert Santoni

Force user to apply settings before going into MIDI learn wizard.

2526. By Sean M. Pappalardo

- Removed unused PrimaryMidiDevice class variable
- White space fix

2527. By Albert Santoni

Fixed RJ's suggestions from merge review. One remaining race condition to solve...

2528. By Albert Santoni

* Add MIDI receive inhibit flag to MidiDevice. Should help us prevent a race condition...
* Removed old MIDI dialog

2529. By Albert Santoni

Fixed more deadlocks

2530. By Sean M. Pappalardo

Removed PM CPPDEFINE since its not used and messes up the SNDFILE one somehow

2531. By Sean M. Pappalardo

Merge with trunk

2532. By Sean M. Pappalardo

- Added preliminary mapping for SCS.3m (in default automatic mode...no direct feedback right now.)
- Added prelminiary single-deck mode for the SCS.3d (to avoid easy deck changes)

2533. By Sean M. Pappalardo

PortTime is needed on Windows and the Linux check works fine for me.

2534. By RJ Skerry-Ryan

Merging from trunk.

2535. By RJ Skerry-Ryan

Unhacking the SConscript

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'mixxx-win64lib/portmidi.h'
2--- mixxx-win64lib/portmidi.h 1970-01-01 00:00:00 +0000
3+++ mixxx-win64lib/portmidi.h 2009-11-10 00:33:17 +0000
4@@ -0,0 +1,604 @@
5+#ifndef PORT_MIDI_H
6+#define PORT_MIDI_H
7+#ifdef __cplusplus
8+extern "C" {
9+#endif /* __cplusplus */
10+
11+/*
12+ * PortMidi Portable Real-Time MIDI Library
13+ * PortMidi API Header File
14+ * Latest version available at: http://sourceforge.net/projects/portmedia
15+ *
16+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
17+ * Copyright (c) 2001-2006 Roger B. Dannenberg
18+ *
19+ * Permission is hereby granted, free of charge, to any person obtaining
20+ * a copy of this software and associated documentation files
21+ * (the "Software"), to deal in the Software without restriction,
22+ * including without limitation the rights to use, copy, modify, merge,
23+ * publish, distribute, sublicense, and/or sell copies of the Software,
24+ * and to permit persons to whom the Software is furnished to do so,
25+ * subject to the following conditions:
26+ *
27+ * The above copyright notice and this permission notice shall be
28+ * included in all copies or substantial portions of the Software.
29+ *
30+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
31+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
32+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
33+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
34+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
35+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
36+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
37+ */
38+
39+/*
40+ * The text above constitutes the entire PortMidi license; however,
41+ * the PortMusic community also makes the following non-binding requests:
42+ *
43+ * Any person wishing to distribute modifications to the Software is
44+ * requested to send the modifications to the original developer so that
45+ * they can be incorporated into the canonical version. It is also
46+ * requested that these non-binding requests be included along with the
47+ * license above.
48+ */
49+
50+/* CHANGELOG FOR PORTMIDI
51+ * (see ../CHANGELOG.txt)
52+ *
53+ * NOTES ON HOST ERROR REPORTING:
54+ *
55+ * PortMidi errors (of type PmError) are generic, system-independent errors.
56+ * When an error does not map to one of the more specific PmErrors, the
57+ * catch-all code pmHostError is returned. This means that PortMidi has
58+ * retained a more specific system-dependent error code. The caller can
59+ * get more information by calling Pm_HasHostError() to test if there is
60+ * a pending host error, and Pm_GetHostErrorText() to get a text string
61+ * describing the error. Host errors are reported on a per-device basis
62+ * because only after you open a device does PortMidi have a place to
63+ * record the host error code. I.e. only
64+ * those routines that receive a (PortMidiStream *) argument check and
65+ * report errors. One exception to this is that Pm_OpenInput() and
66+ * Pm_OpenOutput() can report errors even though when an error occurs,
67+ * there is no PortMidiStream* to hold the error. Fortunately, both
68+ * of these functions return any error immediately, so we do not really
69+ * need per-device error memory. Instead, any host error code is stored
70+ * in a global, pmHostError is returned, and the user can call
71+ * Pm_GetHostErrorText() to get the error message (and the invalid stream
72+ * parameter will be ignored.) The functions
73+ * pm_init and pm_term do not fail or raise
74+ * errors. The job of pm_init is to locate all available devices so that
75+ * the caller can get information via PmDeviceInfo(). If an error occurs,
76+ * the device is simply not listed as available.
77+ *
78+ * Host errors come in two flavors:
79+ * a) host error
80+ * b) host error during callback
81+ * These can occur w/midi input or output devices. (b) can only happen
82+ * asynchronously (during callback routines), whereas (a) only occurs while
83+ * synchronously running PortMidi and any resulting system dependent calls.
84+ * Both (a) and (b) are reported by the next read or write call. You can
85+ * also query for asynchronous errors (b) at any time by calling
86+ * Pm_HasHostError().
87+ *
88+ * NOTES ON COMPILE-TIME SWITCHES
89+ *
90+ * DEBUG assumes stdio and a console. Use this if you want automatic, simple
91+ * error reporting, e.g. for prototyping. If you are using MFC or some
92+ * other graphical interface with no console, DEBUG probably should be
93+ * undefined.
94+ * PM_CHECK_ERRORS more-or-less takes over error checking for return values,
95+ * stopping your program and printing error messages when an error
96+ * occurs. This also uses stdio for console text I/O.
97+ */
98+
99+#ifndef FALSE
100+ #define FALSE 0
101+#endif
102+#ifndef TRUE
103+ #define TRUE 1
104+#endif
105+
106+/* default size of buffers for sysex transmission: */
107+#define PM_DEFAULT_SYSEX_BUFFER_SIZE 1024
108+
109+/** List of portmidi errors.*/
110+typedef enum {
111+ pmNoError = 0,
112+ pmNoData = 0, /**< A "no error" return that also indicates no data avail. */
113+ pmGotData = 1, /**< A "no error" return that also indicates data available */
114+ pmHostError = -10000,
115+ pmInvalidDeviceId, /** out of range or
116+ * output device when input is requested or
117+ * input device when output is requested or
118+ * device is already opened
119+ */
120+ pmInsufficientMemory,
121+ pmBufferTooSmall,
122+ pmBufferOverflow,
123+ pmBadPtr, /* PortMidiStream parameter is NULL or
124+ * stream is not opened or
125+ * stream is output when input is required or
126+ * stream is input when output is required */
127+ pmBadData, /** illegal midi data, e.g. missing EOX */
128+ pmInternalError,
129+ pmBufferMaxSize /** buffer is already as large as it can be */
130+ /* NOTE: If you add a new error type, be sure to update Pm_GetErrorText() */
131+} PmError;
132+
133+/**
134+ Pm_Initialize() is the library initialisation function - call this before
135+ using the library.
136+*/
137+PmError Pm_Initialize( void );
138+
139+/**
140+ Pm_Terminate() is the library termination function - call this after
141+ using the library.
142+*/
143+PmError Pm_Terminate( void );
144+
145+/** A single PortMidiStream is a descriptor for an open MIDI device.
146+*/
147+typedef void PortMidiStream;
148+#define PmStream PortMidiStream
149+
150+/**
151+ Test whether stream has a pending host error. Normally, the client finds
152+ out about errors through returned error codes, but some errors can occur
153+ asynchronously where the client does not
154+ explicitly call a function, and therefore cannot receive an error code.
155+ The client can test for a pending error using Pm_HasHostError(). If true,
156+ the error can be accessed and cleared by calling Pm_GetErrorText().
157+ Errors are also cleared by calling other functions that can return
158+ errors, e.g. Pm_OpenInput(), Pm_OpenOutput(), Pm_Read(), Pm_Write(). The
159+ client does not need to call Pm_HasHostError(). Any pending error will be
160+ reported the next time the client performs an explicit function call on
161+ the stream, e.g. an input or output operation. Until the error is cleared,
162+ no new error codes will be obtained, even for a different stream.
163+*/
164+int Pm_HasHostError( PortMidiStream * stream );
165+
166+
167+/** Translate portmidi error number into human readable message.
168+ These strings are constants (set at compile time) so client has
169+ no need to allocate storage
170+*/
171+const char *Pm_GetErrorText( PmError errnum );
172+
173+/** Translate portmidi host error into human readable message.
174+ These strings are computed at run time, so client has to allocate storage.
175+ After this routine executes, the host error is cleared.
176+*/
177+void Pm_GetHostErrorText(char * msg, unsigned int len);
178+
179+#define HDRLENGTH 50
180+#define PM_HOST_ERROR_MSG_LEN 256u /* any host error msg will occupy less
181+ than this number of characters */
182+
183+/**
184+ Device enumeration mechanism.
185+
186+ Device ids range from 0 to Pm_CountDevices()-1.
187+
188+*/
189+typedef int PmDeviceID;
190+#define pmNoDevice -1
191+typedef struct {
192+ int structVersion; /**< this internal structure version */
193+ const char *interf; /**< underlying MIDI API, e.g. MMSystem or DirectX */
194+ const char *name; /**< device name, e.g. USB MidiSport 1x1 */
195+ int input; /**< true iff input is available */
196+ int output; /**< true iff output is available */
197+ int opened; /**< used by generic PortMidi code to do error checking on arguments */
198+
199+} PmDeviceInfo;
200+
201+/** Get devices count, ids range from 0 to Pm_CountDevices()-1. */
202+int Pm_CountDevices( void );
203+/**
204+ Pm_GetDefaultInputDeviceID(), Pm_GetDefaultOutputDeviceID()
205+
206+ Return the default device ID or pmNoDevice if there are no devices.
207+ The result (but not pmNoDevice) can be passed to Pm_OpenMidi().
208+
209+ The default device can be specified using a small application
210+ named pmdefaults that is part of the PortMidi distribution. This
211+ program in turn uses the Java Preferences object created by
212+ java.util.prefs.Preferences.userRoot().node("/PortMidi"); the
213+ preference is set by calling
214+ prefs.put("PM_RECOMMENDED_OUTPUT_DEVICE", prefName);
215+ or prefs.put("PM_RECOMMENDED_INPUT_DEVICE", prefName);
216+
217+ In the statements above, prefName is a string describing the
218+ MIDI device in the form "interf, name" where interf identifies
219+ the underlying software system or API used by PortMdi to access
220+ devices and name is the name of the device. These correspond to
221+ the interf and name fields of a PmDeviceInfo. (Currently supported
222+ interfaces are "MMSystem" for Win32, "ALSA" for Linux, and
223+ "CoreMIDI" for OS X, so in fact, there is no choice of interface.)
224+ In "interf, name", the strings are actually substrings of
225+ the full interface and name strings. For example, the preference
226+ "Core, Sport" will match a device with interface "CoreMIDI"
227+ and name "In USB MidiSport 1x1". It will also match "CoreMIDI"
228+ and "In USB MidiSport 2x2". The devices are enumerated in device
229+ ID order, so the lowest device ID that matches the pattern becomes
230+ the default device. Finally, if the comma-space (", ") separator
231+ between interface and name parts of the preference is not found,
232+ the entire preference string is interpreted as a name, and the
233+ interface part is the empty string, which matches anything.
234+
235+ On the MAC, preferences are stored in
236+ /Users/$NAME/Library/Preferences/com.apple.java.util.prefs.plist
237+ which is a binary file. In addition to the pmdefaults program,
238+ there are utilities that can read and edit this preference file.
239+
240+ On the PC,
241+
242+ On Linux,
243+
244+*/
245+PmDeviceID Pm_GetDefaultInputDeviceID( void );
246+/** see PmDeviceID Pm_GetDefaultInputDeviceID() */
247+PmDeviceID Pm_GetDefaultOutputDeviceID( void );
248+
249+/**
250+ PmTimestamp is used to represent a millisecond clock with arbitrary
251+ start time. The type is used for all MIDI timestampes and clocks.
252+*/
253+typedef long PmTimestamp;
254+typedef PmTimestamp (*PmTimeProcPtr)(void *time_info);
255+
256+/** TRUE if t1 before t2 */
257+#define PmBefore(t1,t2) ((t1-t2) < 0)
258+/**
259+ \defgroup grp_device Input/Output Devices Handling
260+ @{
261+*/
262+/**
263+ Pm_GetDeviceInfo() returns a pointer to a PmDeviceInfo structure
264+ referring to the device specified by id.
265+ If id is out of range the function returns NULL.
266+
267+ The returned structure is owned by the PortMidi implementation and must
268+ not be manipulated or freed. The pointer is guaranteed to be valid
269+ between calls to Pm_Initialize() and Pm_Terminate().
270+*/
271+const PmDeviceInfo* Pm_GetDeviceInfo( PmDeviceID id );
272+
273+/**
274+ Pm_OpenInput() and Pm_OpenOutput() open devices.
275+
276+ stream is the address of a PortMidiStream pointer which will receive
277+ a pointer to the newly opened stream.
278+
279+ inputDevice is the id of the device used for input (see PmDeviceID above).
280+
281+ inputDriverInfo is a pointer to an optional driver specific data structure
282+ containing additional information for device setup or handle processing.
283+ inputDriverInfo is never required for correct operation. If not used
284+ inputDriverInfo should be NULL.
285+
286+ outputDevice is the id of the device used for output (see PmDeviceID above.)
287+
288+ outputDriverInfo is a pointer to an optional driver specific data structure
289+ containing additional information for device setup or handle processing.
290+ outputDriverInfo is never required for correct operation. If not used
291+ outputDriverInfo should be NULL.
292+
293+ For input, the buffersize specifies the number of input events to be
294+ buffered waiting to be read using Pm_Read(). For output, buffersize
295+ specifies the number of output events to be buffered waiting for output.
296+ (In some cases -- see below -- PortMidi does not buffer output at all
297+ and merely passes data to a lower-level API, in which case buffersize
298+ is ignored.)
299+
300+ latency is the delay in milliseconds applied to timestamps to determine
301+ when the output should actually occur. (If latency is < 0, 0 is assumed.)
302+ If latency is zero, timestamps are ignored and all output is delivered
303+ immediately. If latency is greater than zero, output is delayed until the
304+ message timestamp plus the latency. (NOTE: the time is measured relative
305+ to the time source indicated by time_proc. Timestamps are absolute,
306+ not relative delays or offsets.) In some cases, PortMidi can obtain
307+ better timing than your application by passing timestamps along to the
308+ device driver or hardware. Latency may also help you to synchronize midi
309+ data to audio data by matching midi latency to the audio buffer latency.
310+
311+ time_proc is a pointer to a procedure that returns time in milliseconds. It
312+ may be NULL, in which case a default millisecond timebase (PortTime) is
313+ used. If the application wants to use PortTime, it should start the timer
314+ (call Pt_Start) before calling Pm_OpenInput or Pm_OpenOutput. If the
315+ application tries to start the timer *after* Pm_OpenInput or Pm_OpenOutput,
316+ it may get a ptAlreadyStarted error from Pt_Start, and the application's
317+ preferred time resolution and callback function will be ignored.
318+ time_proc result values are appended to incoming MIDI data, and time_proc
319+ times are used to schedule outgoing MIDI data (when latency is non-zero).
320+
321+ time_info is a pointer passed to time_proc.
322+
323+ Example: If I provide a timestamp of 5000, latency is 1, and time_proc
324+ returns 4990, then the desired output time will be when time_proc returns
325+ timestamp+latency = 5001. This will be 5001-4990 = 11ms from now.
326+
327+ return value:
328+ Upon success Pm_Open() returns PmNoError and places a pointer to a
329+ valid PortMidiStream in the stream argument.
330+ If a call to Pm_Open() fails a nonzero error code is returned (see
331+ PMError above) and the value of port is invalid.
332+
333+ Any stream that is successfully opened should eventually be closed
334+ by calling Pm_Close().
335+
336+*/
337+PmError Pm_OpenInput( PortMidiStream** stream,
338+ PmDeviceID inputDevice,
339+ void *inputDriverInfo,
340+ long bufferSize,
341+ PmTimeProcPtr time_proc,
342+ void *time_info );
343+
344+PmError Pm_OpenOutput( PortMidiStream** stream,
345+ PmDeviceID outputDevice,
346+ void *outputDriverInfo,
347+ long bufferSize,
348+ PmTimeProcPtr time_proc,
349+ void *time_info,
350+ long latency );
351+ /** @} */
352+
353+/**
354+ \defgroup grp_events_filters Events and Filters Handling
355+ @{
356+*/
357+
358+/* \function PmError Pm_SetFilter( PortMidiStream* stream, long filters )
359+ Pm_SetFilter() sets filters on an open input stream to drop selected
360+ input types. By default, only active sensing messages are filtered.
361+ To prohibit, say, active sensing and sysex messages, call
362+ Pm_SetFilter(stream, PM_FILT_ACTIVE | PM_FILT_SYSEX);
363+
364+ Filtering is useful when midi routing or midi thru functionality is being
365+ provided by the user application.
366+ For example, you may want to exclude timing messages (clock, MTC, start/stop/continue),
367+ while allowing note-related messages to pass.
368+ Or you may be using a sequencer or drum-machine for MIDI clock information but want to
369+ exclude any notes it may play.
370+ */
371+
372+/* Filter bit-mask definitions */
373+/** filter active sensing messages (0xFE): */
374+#define PM_FILT_ACTIVE (1 << 0x0E)
375+/** filter system exclusive messages (0xF0): */
376+#define PM_FILT_SYSEX (1 << 0x00)
377+/** filter MIDI clock message (0xF8) */
378+#define PM_FILT_CLOCK (1 << 0x08)
379+/** filter play messages (start 0xFA, stop 0xFC, continue 0xFB) */
380+#define PM_FILT_PLAY ((1 << 0x0A) | (1 << 0x0C) | (1 << 0x0B))
381+/** filter tick messages (0xF9) */
382+#define PM_FILT_TICK (1 << 0x09)
383+/** filter undefined FD messages */
384+#define PM_FILT_FD (1 << 0x0D)
385+/** filter undefined real-time messages */
386+#define PM_FILT_UNDEFINED PM_FILT_FD
387+/** filter reset messages (0xFF) */
388+#define PM_FILT_RESET (1 << 0x0F)
389+/** filter all real-time messages */
390+#define PM_FILT_REALTIME (PM_FILT_ACTIVE | PM_FILT_SYSEX | PM_FILT_CLOCK | \
391+ PM_FILT_PLAY | PM_FILT_UNDEFINED | PM_FILT_RESET | PM_FILT_TICK)
392+/** filter note-on and note-off (0x90-0x9F and 0x80-0x8F */
393+#define PM_FILT_NOTE ((1 << 0x19) | (1 << 0x18))
394+/** filter channel aftertouch (most midi controllers use this) (0xD0-0xDF)*/
395+#define PM_FILT_CHANNEL_AFTERTOUCH (1 << 0x1D)
396+/** per-note aftertouch (0xA0-0xAF) */
397+#define PM_FILT_POLY_AFTERTOUCH (1 << 0x1A)
398+/** filter both channel and poly aftertouch */
399+#define PM_FILT_AFTERTOUCH (PM_FILT_CHANNEL_AFTERTOUCH | PM_FILT_POLY_AFTERTOUCH)
400+/** Program changes (0xC0-0xCF) */
401+#define PM_FILT_PROGRAM (1 << 0x1C)
402+/** Control Changes (CC's) (0xB0-0xBF)*/
403+#define PM_FILT_CONTROL (1 << 0x1B)
404+/** Pitch Bender (0xE0-0xEF*/
405+#define PM_FILT_PITCHBEND (1 << 0x1E)
406+/** MIDI Time Code (0xF1)*/
407+#define PM_FILT_MTC (1 << 0x01)
408+/** Song Position (0xF2) */
409+#define PM_FILT_SONG_POSITION (1 << 0x02)
410+/** Song Select (0xF3)*/
411+#define PM_FILT_SONG_SELECT (1 << 0x03)
412+/** Tuning request (0xF6)*/
413+#define PM_FILT_TUNE (1 << 0x06)
414+/** All System Common messages (mtc, song position, song select, tune request) */
415+#define PM_FILT_SYSTEMCOMMON (PM_FILT_MTC | PM_FILT_SONG_POSITION | PM_FILT_SONG_SELECT | PM_FILT_TUNE)
416+
417+
418+PmError Pm_SetFilter( PortMidiStream* stream, long filters );
419+
420+#define Pm_Channel(channel) (1<<(channel))
421+/**
422+ Pm_SetChannelMask() filters incoming messages based on channel.
423+ The mask is a 16-bit bitfield corresponding to appropriate channels
424+ The Pm_Channel macro can assist in calling this function.
425+ i.e. to set receive only input on channel 1, call with
426+ Pm_SetChannelMask(Pm_Channel(1));
427+ Multiple channels should be OR'd together, like
428+ Pm_SetChannelMask(Pm_Channel(10) | Pm_Channel(11))
429+
430+ All channels are allowed by default
431+*/
432+PmError Pm_SetChannelMask(PortMidiStream *stream, int mask);
433+
434+/**
435+ Pm_Abort() terminates outgoing messages immediately
436+ The caller should immediately close the output port;
437+ this call may result in transmission of a partial midi message.
438+ There is no abort for Midi input because the user can simply
439+ ignore messages in the buffer and close an input device at
440+ any time.
441+ */
442+PmError Pm_Abort( PortMidiStream* stream );
443+
444+/**
445+ Pm_Close() closes a midi stream, flushing any pending buffers.
446+ (PortMidi attempts to close open streams when the application
447+ exits -- this is particularly difficult under Windows.)
448+*/
449+PmError Pm_Close( PortMidiStream* stream );
450+
451+/**
452+ Pm_Message() encodes a short Midi message into a long word. If data1
453+ and/or data2 are not present, use zero.
454+
455+ Pm_MessageStatus(), Pm_MessageData1(), and
456+ Pm_MessageData2() extract fields from a long-encoded midi message.
457+*/
458+#define Pm_Message(status, data1, data2) \
459+ ((((data2) << 16) & 0xFF0000) | \
460+ (((data1) << 8) & 0xFF00) | \
461+ ((status) & 0xFF))
462+#define Pm_MessageStatus(msg) ((msg) & 0xFF)
463+#define Pm_MessageData1(msg) (((msg) >> 8) & 0xFF)
464+#define Pm_MessageData2(msg) (((msg) >> 16) & 0xFF)
465+
466+typedef long PmMessage; /**< see PmEvent */
467+/**
468+ All midi data comes in the form of PmEvent structures. A sysex
469+ message is encoded as a sequence of PmEvent structures, with each
470+ structure carrying 4 bytes of the message, i.e. only the first
471+ PmEvent carries the status byte.
472+
473+ Note that MIDI allows nested messages: the so-called "real-time" MIDI
474+ messages can be inserted into the MIDI byte stream at any location,
475+ including within a sysex message. MIDI real-time messages are one-byte
476+ messages used mainly for timing (see the MIDI spec). PortMidi retains
477+ the order of non-real-time MIDI messages on both input and output, but
478+ it does not specify exactly how real-time messages are processed. This
479+ is particulary problematic for MIDI input, because the input parser
480+ must either prepare to buffer an unlimited number of sysex message
481+ bytes or to buffer an unlimited number of real-time messages that
482+ arrive embedded in a long sysex message. To simplify things, the input
483+ parser is allowed to pass real-time MIDI messages embedded within a
484+ sysex message, and it is up to the client to detect, process, and
485+ remove these messages as they arrive.
486+
487+ When receiving sysex messages, the sysex message is terminated
488+ by either an EOX status byte (anywhere in the 4 byte messages) or
489+ by a non-real-time status byte in the low order byte of the message.
490+ If you get a non-real-time status byte but there was no EOX byte, it
491+ means the sysex message was somehow truncated. This is not
492+ considered an error; e.g., a missing EOX can result from the user
493+ disconnecting a MIDI cable during sysex transmission.
494+
495+ A real-time message can occur within a sysex message. A real-time
496+ message will always occupy a full PmEvent with the status byte in
497+ the low-order byte of the PmEvent message field. (This implies that
498+ the byte-order of sysex bytes and real-time message bytes may not
499+ be preserved -- for example, if a real-time message arrives after
500+ 3 bytes of a sysex message, the real-time message will be delivered
501+ first. The first word of the sysex message will be delivered only
502+ after the 4th byte arrives, filling the 4-byte PmEvent message field.
503+
504+ The timestamp field is observed when the output port is opened with
505+ a non-zero latency. A timestamp of zero means "use the current time",
506+ which in turn means to deliver the message with a delay of
507+ latency (the latency parameter used when opening the output port.)
508+ Do not expect PortMidi to sort data according to timestamps --
509+ messages should be sent in the correct order, and timestamps MUST
510+ be non-decreasing. See also "Example" for Pm_OpenOutput() above.
511+
512+ A sysex message will generally fill many PmEvent structures. On
513+ output to a PortMidiStream with non-zero latency, the first timestamp
514+ on sysex message data will determine the time to begin sending the
515+ message. PortMidi implementations may ignore timestamps for the
516+ remainder of the sysex message.
517+
518+ On input, the timestamp ideally denotes the arrival time of the
519+ status byte of the message. The first timestamp on sysex message
520+ data will be valid. Subsequent timestamps may denote
521+ when message bytes were actually received, or they may be simply
522+ copies of the first timestamp.
523+
524+ Timestamps for nested messages: If a real-time message arrives in
525+ the middle of some other message, it is enqueued immediately with
526+ the timestamp corresponding to its arrival time. The interrupted
527+ non-real-time message or 4-byte packet of sysex data will be enqueued
528+ later. The timestamp of interrupted data will be equal to that of
529+ the interrupting real-time message to insure that timestamps are
530+ non-decreasing.
531+ */
532+typedef struct {
533+ PmMessage message;
534+ PmTimestamp timestamp;
535+} PmEvent;
536+
537+/**
538+ @}
539+*/
540+/** \defgroup grp_io Reading and Writing Midi Messages
541+ @{
542+*/
543+/**
544+ Pm_Read() retrieves midi data into a buffer, and returns the number
545+ of events read. Result is a non-negative number unless an error occurs,
546+ in which case a PmError value will be returned.
547+
548+ Buffer Overflow
549+
550+ The problem: if an input overflow occurs, data will be lost, ultimately
551+ because there is no flow control all the way back to the data source.
552+ When data is lost, the receiver should be notified and some sort of
553+ graceful recovery should take place, e.g. you shouldn't resume receiving
554+ in the middle of a long sysex message.
555+
556+ With a lock-free fifo, which is pretty much what we're stuck with to
557+ enable portability to the Mac, it's tricky for the producer and consumer
558+ to synchronously reset the buffer and resume normal operation.
559+
560+ Solution: the buffer managed by PortMidi will be flushed when an overflow
561+ occurs. The consumer (Pm_Read()) gets an error message (pmBufferOverflow)
562+ and ordinary processing resumes as soon as a new message arrives. The
563+ remainder of a partial sysex message is not considered to be a "new
564+ message" and will be flushed as well.
565+
566+*/
567+int Pm_Read( PortMidiStream *stream, PmEvent *buffer, long length );
568+
569+/**
570+ Pm_Poll() tests whether input is available,
571+ returning TRUE, FALSE, or an error value.
572+*/
573+PmError Pm_Poll( PortMidiStream *stream);
574+
575+/**
576+ Pm_Write() writes midi data from a buffer. This may contain:
577+ - short messages
578+ or
579+ - sysex messages that are converted into a sequence of PmEvent
580+ structures, e.g. sending data from a file or forwarding them
581+ from midi input.
582+
583+ Use Pm_WriteSysEx() to write a sysex message stored as a contiguous
584+ array of bytes.
585+
586+ Sysex data may contain embedded real-time messages.
587+*/
588+PmError Pm_Write( PortMidiStream *stream, PmEvent *buffer, long length );
589+
590+/**
591+ Pm_WriteShort() writes a timestamped non-system-exclusive midi message.
592+ Messages are delivered in order as received, and timestamps must be
593+ non-decreasing. (But timestamps are ignored if the stream was opened
594+ with latency = 0.)
595+*/
596+PmError Pm_WriteShort( PortMidiStream *stream, PmTimestamp when, long msg);
597+
598+/**
599+ Pm_WriteSysEx() writes a timestamped system-exclusive midi message.
600+*/
601+PmError Pm_WriteSysEx( PortMidiStream *stream, PmTimestamp when, unsigned char *msg);
602+
603+/** @} */
604+
605+#ifdef __cplusplus
606+}
607+#endif /* __cplusplus */
608+#endif /* PORT_MIDI_H */
609
610=== added file 'mixxx-win64lib/portmidi.lib'
611Binary files mixxx-win64lib/portmidi.lib 1970-01-01 00:00:00 +0000 and mixxx-win64lib/portmidi.lib 2009-11-10 00:33:17 +0000 differ
612=== added file 'mixxx-win64lib/porttime.h'
613--- mixxx-win64lib/porttime.h 1970-01-01 00:00:00 +0000
614+++ mixxx-win64lib/porttime.h 2009-11-10 00:33:17 +0000
615@@ -0,0 +1,72 @@
616+/* porttime.h -- portable interface to millisecond timer */
617+
618+/* CHANGE LOG FOR PORTTIME
619+ 10-Jun-03 Mark Nelson & RBD
620+ boost priority of timer thread in ptlinux.c implementation
621+ */
622+
623+/* Should there be a way to choose the source of time here? */
624+
625+#ifdef __cplusplus
626+extern "C" {
627+#endif
628+
629+
630+typedef enum {
631+ ptNoError = 0, /* success */
632+ ptHostError = -10000, /* a system-specific error occurred */
633+ ptAlreadyStarted, /* cannot start timer because it is already started */
634+ ptAlreadyStopped, /* cannot stop timer because it is already stopped */
635+ ptInsufficientMemory /* memory could not be allocated */
636+} PtError;
637+
638+
639+typedef long PtTimestamp;
640+
641+typedef void (PtCallback)( PtTimestamp timestamp, void *userData );
642+
643+/*
644+ Pt_Start() starts a real-time service.
645+
646+ resolution is the timer resolution in ms. The time will advance every
647+ resolution ms.
648+
649+ callback is a function pointer to be called every resolution ms.
650+
651+ userData is passed to callback as a parameter.
652+
653+ return value:
654+ Upon success, returns ptNoError. See PtError for other values.
655+*/
656+PtError Pt_Start(int resolution, PtCallback *callback, void *userData);
657+
658+/*
659+ Pt_Stop() stops the timer.
660+
661+ return value:
662+ Upon success, returns ptNoError. See PtError for other values.
663+*/
664+PtError Pt_Stop();
665+
666+/*
667+ Pt_Started() returns true iff the timer is running.
668+*/
669+int Pt_Started();
670+
671+/*
672+ Pt_Time() returns the current time in ms.
673+*/
674+PtTimestamp Pt_Time();
675+
676+/*
677+ Pt_Sleep() pauses, allowing other threads to run.
678+
679+ duration is the length of the pause in ms. The true duration
680+ of the pause may be rounded to the nearest or next clock tick
681+ as determined by resolution in Pt_Start().
682+*/
683+void Pt_Sleep(long duration);
684+
685+#ifdef __cplusplus
686+}
687+#endif
688
689=== added file 'mixxx-win64lib/porttime.lib'
690Binary files mixxx-win64lib/porttime.lib 1970-01-01 00:00:00 +0000 and mixxx-win64lib/porttime.lib 2009-11-10 00:33:17 +0000 differ
691=== added file 'mixxx-winlib/portmidi.h'
692--- mixxx-winlib/portmidi.h 1970-01-01 00:00:00 +0000
693+++ mixxx-winlib/portmidi.h 2009-11-10 00:33:17 +0000
694@@ -0,0 +1,604 @@
695+#ifndef PORT_MIDI_H
696+#define PORT_MIDI_H
697+#ifdef __cplusplus
698+extern "C" {
699+#endif /* __cplusplus */
700+
701+/*
702+ * PortMidi Portable Real-Time MIDI Library
703+ * PortMidi API Header File
704+ * Latest version available at: http://sourceforge.net/projects/portmedia
705+ *
706+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
707+ * Copyright (c) 2001-2006 Roger B. Dannenberg
708+ *
709+ * Permission is hereby granted, free of charge, to any person obtaining
710+ * a copy of this software and associated documentation files
711+ * (the "Software"), to deal in the Software without restriction,
712+ * including without limitation the rights to use, copy, modify, merge,
713+ * publish, distribute, sublicense, and/or sell copies of the Software,
714+ * and to permit persons to whom the Software is furnished to do so,
715+ * subject to the following conditions:
716+ *
717+ * The above copyright notice and this permission notice shall be
718+ * included in all copies or substantial portions of the Software.
719+ *
720+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
721+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
722+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
723+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
724+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
725+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
726+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
727+ */
728+
729+/*
730+ * The text above constitutes the entire PortMidi license; however,
731+ * the PortMusic community also makes the following non-binding requests:
732+ *
733+ * Any person wishing to distribute modifications to the Software is
734+ * requested to send the modifications to the original developer so that
735+ * they can be incorporated into the canonical version. It is also
736+ * requested that these non-binding requests be included along with the
737+ * license above.
738+ */
739+
740+/* CHANGELOG FOR PORTMIDI
741+ * (see ../CHANGELOG.txt)
742+ *
743+ * NOTES ON HOST ERROR REPORTING:
744+ *
745+ * PortMidi errors (of type PmError) are generic, system-independent errors.
746+ * When an error does not map to one of the more specific PmErrors, the
747+ * catch-all code pmHostError is returned. This means that PortMidi has
748+ * retained a more specific system-dependent error code. The caller can
749+ * get more information by calling Pm_HasHostError() to test if there is
750+ * a pending host error, and Pm_GetHostErrorText() to get a text string
751+ * describing the error. Host errors are reported on a per-device basis
752+ * because only after you open a device does PortMidi have a place to
753+ * record the host error code. I.e. only
754+ * those routines that receive a (PortMidiStream *) argument check and
755+ * report errors. One exception to this is that Pm_OpenInput() and
756+ * Pm_OpenOutput() can report errors even though when an error occurs,
757+ * there is no PortMidiStream* to hold the error. Fortunately, both
758+ * of these functions return any error immediately, so we do not really
759+ * need per-device error memory. Instead, any host error code is stored
760+ * in a global, pmHostError is returned, and the user can call
761+ * Pm_GetHostErrorText() to get the error message (and the invalid stream
762+ * parameter will be ignored.) The functions
763+ * pm_init and pm_term do not fail or raise
764+ * errors. The job of pm_init is to locate all available devices so that
765+ * the caller can get information via PmDeviceInfo(). If an error occurs,
766+ * the device is simply not listed as available.
767+ *
768+ * Host errors come in two flavors:
769+ * a) host error
770+ * b) host error during callback
771+ * These can occur w/midi input or output devices. (b) can only happen
772+ * asynchronously (during callback routines), whereas (a) only occurs while
773+ * synchronously running PortMidi and any resulting system dependent calls.
774+ * Both (a) and (b) are reported by the next read or write call. You can
775+ * also query for asynchronous errors (b) at any time by calling
776+ * Pm_HasHostError().
777+ *
778+ * NOTES ON COMPILE-TIME SWITCHES
779+ *
780+ * DEBUG assumes stdio and a console. Use this if you want automatic, simple
781+ * error reporting, e.g. for prototyping. If you are using MFC or some
782+ * other graphical interface with no console, DEBUG probably should be
783+ * undefined.
784+ * PM_CHECK_ERRORS more-or-less takes over error checking for return values,
785+ * stopping your program and printing error messages when an error
786+ * occurs. This also uses stdio for console text I/O.
787+ */
788+
789+#ifndef FALSE
790+ #define FALSE 0
791+#endif
792+#ifndef TRUE
793+ #define TRUE 1
794+#endif
795+
796+/* default size of buffers for sysex transmission: */
797+#define PM_DEFAULT_SYSEX_BUFFER_SIZE 1024
798+
799+/** List of portmidi errors.*/
800+typedef enum {
801+ pmNoError = 0,
802+ pmNoData = 0, /**< A "no error" return that also indicates no data avail. */
803+ pmGotData = 1, /**< A "no error" return that also indicates data available */
804+ pmHostError = -10000,
805+ pmInvalidDeviceId, /** out of range or
806+ * output device when input is requested or
807+ * input device when output is requested or
808+ * device is already opened
809+ */
810+ pmInsufficientMemory,
811+ pmBufferTooSmall,
812+ pmBufferOverflow,
813+ pmBadPtr, /* PortMidiStream parameter is NULL or
814+ * stream is not opened or
815+ * stream is output when input is required or
816+ * stream is input when output is required */
817+ pmBadData, /** illegal midi data, e.g. missing EOX */
818+ pmInternalError,
819+ pmBufferMaxSize /** buffer is already as large as it can be */
820+ /* NOTE: If you add a new error type, be sure to update Pm_GetErrorText() */
821+} PmError;
822+
823+/**
824+ Pm_Initialize() is the library initialisation function - call this before
825+ using the library.
826+*/
827+PmError Pm_Initialize( void );
828+
829+/**
830+ Pm_Terminate() is the library termination function - call this after
831+ using the library.
832+*/
833+PmError Pm_Terminate( void );
834+
835+/** A single PortMidiStream is a descriptor for an open MIDI device.
836+*/
837+typedef void PortMidiStream;
838+#define PmStream PortMidiStream
839+
840+/**
841+ Test whether stream has a pending host error. Normally, the client finds
842+ out about errors through returned error codes, but some errors can occur
843+ asynchronously where the client does not
844+ explicitly call a function, and therefore cannot receive an error code.
845+ The client can test for a pending error using Pm_HasHostError(). If true,
846+ the error can be accessed and cleared by calling Pm_GetErrorText().
847+ Errors are also cleared by calling other functions that can return
848+ errors, e.g. Pm_OpenInput(), Pm_OpenOutput(), Pm_Read(), Pm_Write(). The
849+ client does not need to call Pm_HasHostError(). Any pending error will be
850+ reported the next time the client performs an explicit function call on
851+ the stream, e.g. an input or output operation. Until the error is cleared,
852+ no new error codes will be obtained, even for a different stream.
853+*/
854+int Pm_HasHostError( PortMidiStream * stream );
855+
856+
857+/** Translate portmidi error number into human readable message.
858+ These strings are constants (set at compile time) so client has
859+ no need to allocate storage
860+*/
861+const char *Pm_GetErrorText( PmError errnum );
862+
863+/** Translate portmidi host error into human readable message.
864+ These strings are computed at run time, so client has to allocate storage.
865+ After this routine executes, the host error is cleared.
866+*/
867+void Pm_GetHostErrorText(char * msg, unsigned int len);
868+
869+#define HDRLENGTH 50
870+#define PM_HOST_ERROR_MSG_LEN 256u /* any host error msg will occupy less
871+ than this number of characters */
872+
873+/**
874+ Device enumeration mechanism.
875+
876+ Device ids range from 0 to Pm_CountDevices()-1.
877+
878+*/
879+typedef int PmDeviceID;
880+#define pmNoDevice -1
881+typedef struct {
882+ int structVersion; /**< this internal structure version */
883+ const char *interf; /**< underlying MIDI API, e.g. MMSystem or DirectX */
884+ const char *name; /**< device name, e.g. USB MidiSport 1x1 */
885+ int input; /**< true iff input is available */
886+ int output; /**< true iff output is available */
887+ int opened; /**< used by generic PortMidi code to do error checking on arguments */
888+
889+} PmDeviceInfo;
890+
891+/** Get devices count, ids range from 0 to Pm_CountDevices()-1. */
892+int Pm_CountDevices( void );
893+/**
894+ Pm_GetDefaultInputDeviceID(), Pm_GetDefaultOutputDeviceID()
895+
896+ Return the default device ID or pmNoDevice if there are no devices.
897+ The result (but not pmNoDevice) can be passed to Pm_OpenMidi().
898+
899+ The default device can be specified using a small application
900+ named pmdefaults that is part of the PortMidi distribution. This
901+ program in turn uses the Java Preferences object created by
902+ java.util.prefs.Preferences.userRoot().node("/PortMidi"); the
903+ preference is set by calling
904+ prefs.put("PM_RECOMMENDED_OUTPUT_DEVICE", prefName);
905+ or prefs.put("PM_RECOMMENDED_INPUT_DEVICE", prefName);
906+
907+ In the statements above, prefName is a string describing the
908+ MIDI device in the form "interf, name" where interf identifies
909+ the underlying software system or API used by PortMdi to access
910+ devices and name is the name of the device. These correspond to
911+ the interf and name fields of a PmDeviceInfo. (Currently supported
912+ interfaces are "MMSystem" for Win32, "ALSA" for Linux, and
913+ "CoreMIDI" for OS X, so in fact, there is no choice of interface.)
914+ In "interf, name", the strings are actually substrings of
915+ the full interface and name strings. For example, the preference
916+ "Core, Sport" will match a device with interface "CoreMIDI"
917+ and name "In USB MidiSport 1x1". It will also match "CoreMIDI"
918+ and "In USB MidiSport 2x2". The devices are enumerated in device
919+ ID order, so the lowest device ID that matches the pattern becomes
920+ the default device. Finally, if the comma-space (", ") separator
921+ between interface and name parts of the preference is not found,
922+ the entire preference string is interpreted as a name, and the
923+ interface part is the empty string, which matches anything.
924+
925+ On the MAC, preferences are stored in
926+ /Users/$NAME/Library/Preferences/com.apple.java.util.prefs.plist
927+ which is a binary file. In addition to the pmdefaults program,
928+ there are utilities that can read and edit this preference file.
929+
930+ On the PC,
931+
932+ On Linux,
933+
934+*/
935+PmDeviceID Pm_GetDefaultInputDeviceID( void );
936+/** see PmDeviceID Pm_GetDefaultInputDeviceID() */
937+PmDeviceID Pm_GetDefaultOutputDeviceID( void );
938+
939+/**
940+ PmTimestamp is used to represent a millisecond clock with arbitrary
941+ start time. The type is used for all MIDI timestampes and clocks.
942+*/
943+typedef long PmTimestamp;
944+typedef PmTimestamp (*PmTimeProcPtr)(void *time_info);
945+
946+/** TRUE if t1 before t2 */
947+#define PmBefore(t1,t2) ((t1-t2) < 0)
948+/**
949+ \defgroup grp_device Input/Output Devices Handling
950+ @{
951+*/
952+/**
953+ Pm_GetDeviceInfo() returns a pointer to a PmDeviceInfo structure
954+ referring to the device specified by id.
955+ If id is out of range the function returns NULL.
956+
957+ The returned structure is owned by the PortMidi implementation and must
958+ not be manipulated or freed. The pointer is guaranteed to be valid
959+ between calls to Pm_Initialize() and Pm_Terminate().
960+*/
961+const PmDeviceInfo* Pm_GetDeviceInfo( PmDeviceID id );
962+
963+/**
964+ Pm_OpenInput() and Pm_OpenOutput() open devices.
965+
966+ stream is the address of a PortMidiStream pointer which will receive
967+ a pointer to the newly opened stream.
968+
969+ inputDevice is the id of the device used for input (see PmDeviceID above).
970+
971+ inputDriverInfo is a pointer to an optional driver specific data structure
972+ containing additional information for device setup or handle processing.
973+ inputDriverInfo is never required for correct operation. If not used
974+ inputDriverInfo should be NULL.
975+
976+ outputDevice is the id of the device used for output (see PmDeviceID above.)
977+
978+ outputDriverInfo is a pointer to an optional driver specific data structure
979+ containing additional information for device setup or handle processing.
980+ outputDriverInfo is never required for correct operation. If not used
981+ outputDriverInfo should be NULL.
982+
983+ For input, the buffersize specifies the number of input events to be
984+ buffered waiting to be read using Pm_Read(). For output, buffersize
985+ specifies the number of output events to be buffered waiting for output.
986+ (In some cases -- see below -- PortMidi does not buffer output at all
987+ and merely passes data to a lower-level API, in which case buffersize
988+ is ignored.)
989+
990+ latency is the delay in milliseconds applied to timestamps to determine
991+ when the output should actually occur. (If latency is < 0, 0 is assumed.)
992+ If latency is zero, timestamps are ignored and all output is delivered
993+ immediately. If latency is greater than zero, output is delayed until the
994+ message timestamp plus the latency. (NOTE: the time is measured relative
995+ to the time source indicated by time_proc. Timestamps are absolute,
996+ not relative delays or offsets.) In some cases, PortMidi can obtain
997+ better timing than your application by passing timestamps along to the
998+ device driver or hardware. Latency may also help you to synchronize midi
999+ data to audio data by matching midi latency to the audio buffer latency.
1000+
1001+ time_proc is a pointer to a procedure that returns time in milliseconds. It
1002+ may be NULL, in which case a default millisecond timebase (PortTime) is
1003+ used. If the application wants to use PortTime, it should start the timer
1004+ (call Pt_Start) before calling Pm_OpenInput or Pm_OpenOutput. If the
1005+ application tries to start the timer *after* Pm_OpenInput or Pm_OpenOutput,
1006+ it may get a ptAlreadyStarted error from Pt_Start, and the application's
1007+ preferred time resolution and callback function will be ignored.
1008+ time_proc result values are appended to incoming MIDI data, and time_proc
1009+ times are used to schedule outgoing MIDI data (when latency is non-zero).
1010+
1011+ time_info is a pointer passed to time_proc.
1012+
1013+ Example: If I provide a timestamp of 5000, latency is 1, and time_proc
1014+ returns 4990, then the desired output time will be when time_proc returns
1015+ timestamp+latency = 5001. This will be 5001-4990 = 11ms from now.
1016+
1017+ return value:
1018+ Upon success Pm_Open() returns PmNoError and places a pointer to a
1019+ valid PortMidiStream in the stream argument.
1020+ If a call to Pm_Open() fails a nonzero error code is returned (see
1021+ PMError above) and the value of port is invalid.
1022+
1023+ Any stream that is successfully opened should eventually be closed
1024+ by calling Pm_Close().
1025+
1026+*/
1027+PmError Pm_OpenInput( PortMidiStream** stream,
1028+ PmDeviceID inputDevice,
1029+ void *inputDriverInfo,
1030+ long bufferSize,
1031+ PmTimeProcPtr time_proc,
1032+ void *time_info );
1033+
1034+PmError Pm_OpenOutput( PortMidiStream** stream,
1035+ PmDeviceID outputDevice,
1036+ void *outputDriverInfo,
1037+ long bufferSize,
1038+ PmTimeProcPtr time_proc,
1039+ void *time_info,
1040+ long latency );
1041+ /** @} */
1042+
1043+/**
1044+ \defgroup grp_events_filters Events and Filters Handling
1045+ @{
1046+*/
1047+
1048+/* \function PmError Pm_SetFilter( PortMidiStream* stream, long filters )
1049+ Pm_SetFilter() sets filters on an open input stream to drop selected
1050+ input types. By default, only active sensing messages are filtered.
1051+ To prohibit, say, active sensing and sysex messages, call
1052+ Pm_SetFilter(stream, PM_FILT_ACTIVE | PM_FILT_SYSEX);
1053+
1054+ Filtering is useful when midi routing or midi thru functionality is being
1055+ provided by the user application.
1056+ For example, you may want to exclude timing messages (clock, MTC, start/stop/continue),
1057+ while allowing note-related messages to pass.
1058+ Or you may be using a sequencer or drum-machine for MIDI clock information but want to
1059+ exclude any notes it may play.
1060+ */
1061+
1062+/* Filter bit-mask definitions */
1063+/** filter active sensing messages (0xFE): */
1064+#define PM_FILT_ACTIVE (1 << 0x0E)
1065+/** filter system exclusive messages (0xF0): */
1066+#define PM_FILT_SYSEX (1 << 0x00)
1067+/** filter MIDI clock message (0xF8) */
1068+#define PM_FILT_CLOCK (1 << 0x08)
1069+/** filter play messages (start 0xFA, stop 0xFC, continue 0xFB) */
1070+#define PM_FILT_PLAY ((1 << 0x0A) | (1 << 0x0C) | (1 << 0x0B))
1071+/** filter tick messages (0xF9) */
1072+#define PM_FILT_TICK (1 << 0x09)
1073+/** filter undefined FD messages */
1074+#define PM_FILT_FD (1 << 0x0D)
1075+/** filter undefined real-time messages */
1076+#define PM_FILT_UNDEFINED PM_FILT_FD
1077+/** filter reset messages (0xFF) */
1078+#define PM_FILT_RESET (1 << 0x0F)
1079+/** filter all real-time messages */
1080+#define PM_FILT_REALTIME (PM_FILT_ACTIVE | PM_FILT_SYSEX | PM_FILT_CLOCK | \
1081+ PM_FILT_PLAY | PM_FILT_UNDEFINED | PM_FILT_RESET | PM_FILT_TICK)
1082+/** filter note-on and note-off (0x90-0x9F and 0x80-0x8F */
1083+#define PM_FILT_NOTE ((1 << 0x19) | (1 << 0x18))
1084+/** filter channel aftertouch (most midi controllers use this) (0xD0-0xDF)*/
1085+#define PM_FILT_CHANNEL_AFTERTOUCH (1 << 0x1D)
1086+/** per-note aftertouch (0xA0-0xAF) */
1087+#define PM_FILT_POLY_AFTERTOUCH (1 << 0x1A)
1088+/** filter both channel and poly aftertouch */
1089+#define PM_FILT_AFTERTOUCH (PM_FILT_CHANNEL_AFTERTOUCH | PM_FILT_POLY_AFTERTOUCH)
1090+/** Program changes (0xC0-0xCF) */
1091+#define PM_FILT_PROGRAM (1 << 0x1C)
1092+/** Control Changes (CC's) (0xB0-0xBF)*/
1093+#define PM_FILT_CONTROL (1 << 0x1B)
1094+/** Pitch Bender (0xE0-0xEF*/
1095+#define PM_FILT_PITCHBEND (1 << 0x1E)
1096+/** MIDI Time Code (0xF1)*/
1097+#define PM_FILT_MTC (1 << 0x01)
1098+/** Song Position (0xF2) */
1099+#define PM_FILT_SONG_POSITION (1 << 0x02)
1100+/** Song Select (0xF3)*/
1101+#define PM_FILT_SONG_SELECT (1 << 0x03)
1102+/** Tuning request (0xF6)*/
1103+#define PM_FILT_TUNE (1 << 0x06)
1104+/** All System Common messages (mtc, song position, song select, tune request) */
1105+#define PM_FILT_SYSTEMCOMMON (PM_FILT_MTC | PM_FILT_SONG_POSITION | PM_FILT_SONG_SELECT | PM_FILT_TUNE)
1106+
1107+
1108+PmError Pm_SetFilter( PortMidiStream* stream, long filters );
1109+
1110+#define Pm_Channel(channel) (1<<(channel))
1111+/**
1112+ Pm_SetChannelMask() filters incoming messages based on channel.
1113+ The mask is a 16-bit bitfield corresponding to appropriate channels
1114+ The Pm_Channel macro can assist in calling this function.
1115+ i.e. to set receive only input on channel 1, call with
1116+ Pm_SetChannelMask(Pm_Channel(1));
1117+ Multiple channels should be OR'd together, like
1118+ Pm_SetChannelMask(Pm_Channel(10) | Pm_Channel(11))
1119+
1120+ All channels are allowed by default
1121+*/
1122+PmError Pm_SetChannelMask(PortMidiStream *stream, int mask);
1123+
1124+/**
1125+ Pm_Abort() terminates outgoing messages immediately
1126+ The caller should immediately close the output port;
1127+ this call may result in transmission of a partial midi message.
1128+ There is no abort for Midi input because the user can simply
1129+ ignore messages in the buffer and close an input device at
1130+ any time.
1131+ */
1132+PmError Pm_Abort( PortMidiStream* stream );
1133+
1134+/**
1135+ Pm_Close() closes a midi stream, flushing any pending buffers.
1136+ (PortMidi attempts to close open streams when the application
1137+ exits -- this is particularly difficult under Windows.)
1138+*/
1139+PmError Pm_Close( PortMidiStream* stream );
1140+
1141+/**
1142+ Pm_Message() encodes a short Midi message into a long word. If data1
1143+ and/or data2 are not present, use zero.
1144+
1145+ Pm_MessageStatus(), Pm_MessageData1(), and
1146+ Pm_MessageData2() extract fields from a long-encoded midi message.
1147+*/
1148+#define Pm_Message(status, data1, data2) \
1149+ ((((data2) << 16) & 0xFF0000) | \
1150+ (((data1) << 8) & 0xFF00) | \
1151+ ((status) & 0xFF))
1152+#define Pm_MessageStatus(msg) ((msg) & 0xFF)
1153+#define Pm_MessageData1(msg) (((msg) >> 8) & 0xFF)
1154+#define Pm_MessageData2(msg) (((msg) >> 16) & 0xFF)
1155+
1156+typedef long PmMessage; /**< see PmEvent */
1157+/**
1158+ All midi data comes in the form of PmEvent structures. A sysex
1159+ message is encoded as a sequence of PmEvent structures, with each
1160+ structure carrying 4 bytes of the message, i.e. only the first
1161+ PmEvent carries the status byte.
1162+
1163+ Note that MIDI allows nested messages: the so-called "real-time" MIDI
1164+ messages can be inserted into the MIDI byte stream at any location,
1165+ including within a sysex message. MIDI real-time messages are one-byte
1166+ messages used mainly for timing (see the MIDI spec). PortMidi retains
1167+ the order of non-real-time MIDI messages on both input and output, but
1168+ it does not specify exactly how real-time messages are processed. This
1169+ is particulary problematic for MIDI input, because the input parser
1170+ must either prepare to buffer an unlimited number of sysex message
1171+ bytes or to buffer an unlimited number of real-time messages that
1172+ arrive embedded in a long sysex message. To simplify things, the input
1173+ parser is allowed to pass real-time MIDI messages embedded within a
1174+ sysex message, and it is up to the client to detect, process, and
1175+ remove these messages as they arrive.
1176+
1177+ When receiving sysex messages, the sysex message is terminated
1178+ by either an EOX status byte (anywhere in the 4 byte messages) or
1179+ by a non-real-time status byte in the low order byte of the message.
1180+ If you get a non-real-time status byte but there was no EOX byte, it
1181+ means the sysex message was somehow truncated. This is not
1182+ considered an error; e.g., a missing EOX can result from the user
1183+ disconnecting a MIDI cable during sysex transmission.
1184+
1185+ A real-time message can occur within a sysex message. A real-time
1186+ message will always occupy a full PmEvent with the status byte in
1187+ the low-order byte of the PmEvent message field. (This implies that
1188+ the byte-order of sysex bytes and real-time message bytes may not
1189+ be preserved -- for example, if a real-time message arrives after
1190+ 3 bytes of a sysex message, the real-time message will be delivered
1191+ first. The first word of the sysex message will be delivered only
1192+ after the 4th byte arrives, filling the 4-byte PmEvent message field.
1193+
1194+ The timestamp field is observed when the output port is opened with
1195+ a non-zero latency. A timestamp of zero means "use the current time",
1196+ which in turn means to deliver the message with a delay of
1197+ latency (the latency parameter used when opening the output port.)
1198+ Do not expect PortMidi to sort data according to timestamps --
1199+ messages should be sent in the correct order, and timestamps MUST
1200+ be non-decreasing. See also "Example" for Pm_OpenOutput() above.
1201+
1202+ A sysex message will generally fill many PmEvent structures. On
1203+ output to a PortMidiStream with non-zero latency, the first timestamp
1204+ on sysex message data will determine the time to begin sending the
1205+ message. PortMidi implementations may ignore timestamps for the
1206+ remainder of the sysex message.
1207+
1208+ On input, the timestamp ideally denotes the arrival time of the
1209+ status byte of the message. The first timestamp on sysex message
1210+ data will be valid. Subsequent timestamps may denote
1211+ when message bytes were actually received, or they may be simply
1212+ copies of the first timestamp.
1213+
1214+ Timestamps for nested messages: If a real-time message arrives in
1215+ the middle of some other message, it is enqueued immediately with
1216+ the timestamp corresponding to its arrival time. The interrupted
1217+ non-real-time message or 4-byte packet of sysex data will be enqueued
1218+ later. The timestamp of interrupted data will be equal to that of
1219+ the interrupting real-time message to insure that timestamps are
1220+ non-decreasing.
1221+ */
1222+typedef struct {
1223+ PmMessage message;
1224+ PmTimestamp timestamp;
1225+} PmEvent;
1226+
1227+/**
1228+ @}
1229+*/
1230+/** \defgroup grp_io Reading and Writing Midi Messages
1231+ @{
1232+*/
1233+/**
1234+ Pm_Read() retrieves midi data into a buffer, and returns the number
1235+ of events read. Result is a non-negative number unless an error occurs,
1236+ in which case a PmError value will be returned.
1237+
1238+ Buffer Overflow
1239+
1240+ The problem: if an input overflow occurs, data will be lost, ultimately
1241+ because there is no flow control all the way back to the data source.
1242+ When data is lost, the receiver should be notified and some sort of
1243+ graceful recovery should take place, e.g. you shouldn't resume receiving
1244+ in the middle of a long sysex message.
1245+
1246+ With a lock-free fifo, which is pretty much what we're stuck with to
1247+ enable portability to the Mac, it's tricky for the producer and consumer
1248+ to synchronously reset the buffer and resume normal operation.
1249+
1250+ Solution: the buffer managed by PortMidi will be flushed when an overflow
1251+ occurs. The consumer (Pm_Read()) gets an error message (pmBufferOverflow)
1252+ and ordinary processing resumes as soon as a new message arrives. The
1253+ remainder of a partial sysex message is not considered to be a "new
1254+ message" and will be flushed as well.
1255+
1256+*/
1257+int Pm_Read( PortMidiStream *stream, PmEvent *buffer, long length );
1258+
1259+/**
1260+ Pm_Poll() tests whether input is available,
1261+ returning TRUE, FALSE, or an error value.
1262+*/
1263+PmError Pm_Poll( PortMidiStream *stream);
1264+
1265+/**
1266+ Pm_Write() writes midi data from a buffer. This may contain:
1267+ - short messages
1268+ or
1269+ - sysex messages that are converted into a sequence of PmEvent
1270+ structures, e.g. sending data from a file or forwarding them
1271+ from midi input.
1272+
1273+ Use Pm_WriteSysEx() to write a sysex message stored as a contiguous
1274+ array of bytes.
1275+
1276+ Sysex data may contain embedded real-time messages.
1277+*/
1278+PmError Pm_Write( PortMidiStream *stream, PmEvent *buffer, long length );
1279+
1280+/**
1281+ Pm_WriteShort() writes a timestamped non-system-exclusive midi message.
1282+ Messages are delivered in order as received, and timestamps must be
1283+ non-decreasing. (But timestamps are ignored if the stream was opened
1284+ with latency = 0.)
1285+*/
1286+PmError Pm_WriteShort( PortMidiStream *stream, PmTimestamp when, long msg);
1287+
1288+/**
1289+ Pm_WriteSysEx() writes a timestamped system-exclusive midi message.
1290+*/
1291+PmError Pm_WriteSysEx( PortMidiStream *stream, PmTimestamp when, unsigned char *msg);
1292+
1293+/** @} */
1294+
1295+#ifdef __cplusplus
1296+}
1297+#endif /* __cplusplus */
1298+#endif /* PORT_MIDI_H */
1299
1300=== added file 'mixxx-winlib/portmidi.lib'
1301Binary files mixxx-winlib/portmidi.lib 1970-01-01 00:00:00 +0000 and mixxx-winlib/portmidi.lib 2009-11-10 00:33:17 +0000 differ
1302=== added file 'mixxx-winlib/porttime.h'
1303--- mixxx-winlib/porttime.h 1970-01-01 00:00:00 +0000
1304+++ mixxx-winlib/porttime.h 2009-11-10 00:33:17 +0000
1305@@ -0,0 +1,72 @@
1306+/* porttime.h -- portable interface to millisecond timer */
1307+
1308+/* CHANGE LOG FOR PORTTIME
1309+ 10-Jun-03 Mark Nelson & RBD
1310+ boost priority of timer thread in ptlinux.c implementation
1311+ */
1312+
1313+/* Should there be a way to choose the source of time here? */
1314+
1315+#ifdef __cplusplus
1316+extern "C" {
1317+#endif
1318+
1319+
1320+typedef enum {
1321+ ptNoError = 0, /* success */
1322+ ptHostError = -10000, /* a system-specific error occurred */
1323+ ptAlreadyStarted, /* cannot start timer because it is already started */
1324+ ptAlreadyStopped, /* cannot stop timer because it is already stopped */
1325+ ptInsufficientMemory /* memory could not be allocated */
1326+} PtError;
1327+
1328+
1329+typedef long PtTimestamp;
1330+
1331+typedef void (PtCallback)( PtTimestamp timestamp, void *userData );
1332+
1333+/*
1334+ Pt_Start() starts a real-time service.
1335+
1336+ resolution is the timer resolution in ms. The time will advance every
1337+ resolution ms.
1338+
1339+ callback is a function pointer to be called every resolution ms.
1340+
1341+ userData is passed to callback as a parameter.
1342+
1343+ return value:
1344+ Upon success, returns ptNoError. See PtError for other values.
1345+*/
1346+PtError Pt_Start(int resolution, PtCallback *callback, void *userData);
1347+
1348+/*
1349+ Pt_Stop() stops the timer.
1350+
1351+ return value:
1352+ Upon success, returns ptNoError. See PtError for other values.
1353+*/
1354+PtError Pt_Stop();
1355+
1356+/*
1357+ Pt_Started() returns true iff the timer is running.
1358+*/
1359+int Pt_Started();
1360+
1361+/*
1362+ Pt_Time() returns the current time in ms.
1363+*/
1364+PtTimestamp Pt_Time();
1365+
1366+/*
1367+ Pt_Sleep() pauses, allowing other threads to run.
1368+
1369+ duration is the length of the pause in ms. The true duration
1370+ of the pause may be rounded to the nearest or next clock tick
1371+ as determined by resolution in Pt_Start().
1372+*/
1373+void Pt_Sleep(long duration);
1374+
1375+#ifdef __cplusplus
1376+}
1377+#endif
1378
1379=== added file 'mixxx-winlib/porttime.lib'
1380Binary files mixxx-winlib/porttime.lib 1970-01-01 00:00:00 +0000 and mixxx-winlib/porttime.lib 2009-11-10 00:33:17 +0000 differ
1381=== added file 'mixxx/Mixxx.nsi'
1382--- mixxx/Mixxx.nsi 1970-01-01 00:00:00 +0000
1383+++ mixxx/Mixxx.nsi 2009-08-11 04:38:51 +0000
1384@@ -0,0 +1,255 @@
1385+; Mixxx.nsi
1386+;
1387+; Mixxx NSI install script.
1388+; has uninstall support and (optionally) installs start menu shortcuts.
1389+;
1390+; By Tue Haste Andersen <haste@diku.dk>, June 2004.
1391+; Heavily modified since by Albert Santoni, Garth Dahlstrom and Sean Pappalardo.
1392+;
1393+; Lots of bits lifted from http://www.improve.dk/downloads/InstallScript.txt
1394+;
1395+;Include Modern UI
1396+!include "MUI.nsh"
1397+
1398+; Definitions
1399+!define PRODUCT_NAME "Mixxx"
1400+;!define PRODUCT_VERSION "" ; Specified by the SConscript
1401+!define PRODUCT_PUBLISHER "The Mixxx Team"
1402+!define PRODUCT_WEB_SITE "http://www.mixxx.org"
1403+!define PRODUCT_DIR_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\Mixxx.exe"
1404+!define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
1405+!define PRODUCT_UNINST_ROOT_KEY "HKLM"
1406+
1407+; The name of the installer
1408+Name "${PRODUCT_NAME} ${PRODUCT_VERSION}"
1409+
1410+; Disable the Nullsoft Installer branding text at the bottom.
1411+BrandingText " "
1412+
1413+; The file to write and default installation directory
1414+!ifdef x64
1415+ OutFile "${PRODUCT_NAME}-${PRODUCT_VERSION}-x64.exe"
1416+ InstallDir "$PROGRAMFILES64\${PRODUCT_NAME}"
1417+!else
1418+ OutFile "${PRODUCT_NAME}-${PRODUCT_VERSION}-x86.exe"
1419+ InstallDir "$PROGRAMFILES\${PRODUCT_NAME}"
1420+!endif
1421+
1422+; Use best compression
1423+SetCompressor /SOLID lzma
1424+
1425+; Registry key to check for directory (so if you install again, it will
1426+; overwrite the old one automatically)
1427+;InstallDirRegKey HKLM "Software\NSIS_Mixxx" "Install_Dir"
1428+InstallDirRegKey HKLM "${PRODUCT_DIR_REGKEY}" ""
1429+
1430+;Interface Settings
1431+!define MUI_ABORTWARNING
1432+
1433+!define MUI_HEADERIMAGE
1434+;!define MUI_HEADERIMAGE_RIGHT
1435+!define MUI_HEADERIMAGE_BITMAP_NOSTRETCH
1436+!define MUI_HEADERIMAGE_BITMAP "res\images\mixxx_install_logo.bmp"
1437+!define MUI_ICON "res\images\icon.ico"
1438+
1439+; Pages
1440+!insertmacro MUI_PAGE_LICENSE "LICENSE"
1441+!insertmacro MUI_PAGE_COMPONENTS
1442+!insertmacro MUI_PAGE_DIRECTORY
1443+!insertmacro MUI_PAGE_INSTFILES
1444+
1445+!insertmacro MUI_UNPAGE_CONFIRM
1446+!insertmacro MUI_UNPAGE_INSTFILES
1447+
1448+;Languages
1449+!insertmacro MUI_LANGUAGE "English"
1450+
1451+;--------------------------------
1452+; Install functions
1453+
1454+Function .onInit ; Prevent multiple installer instances
1455+ System::Call 'kernel32::CreateMutexA(i 0, i 0, t "runningMixxxInstallerMutex") i .r1 ?e'
1456+ Pop $R0
1457+
1458+ StrCmp $R0 0 +3
1459+ MessageBox MB_OK|MB_ICONEXCLAMATION "The installer is already running."
1460+ Abort
1461+FunctionEnd
1462+
1463+;--------------------------------
1464+; The stuff to install
1465+Section "Mixxx (required)" SecMixxx
1466+
1467+ SectionIn RO
1468+
1469+ ; Set output path to the installation directory.
1470+ SetOutPath $INSTDIR
1471+
1472+ ; Put binary files there
1473+ File "dist\mixxx.exe"
1474+ File "dist\*.dll"
1475+
1476+ ; NOTE: you need to check the mixxx.exe.manifest file in the win??_build directory
1477+ ; and place the appropriate versions of the listed DLL files and their manifest files
1478+ ; into the mixxx-win[64]lib directory for packaging before making the installer
1479+ ; (Visual C++ 2005 is msvc?80.dll and Microsoft.VC80.CRT.manifest, Visual C++ 2008 is msvc?90.dll and Microsoft.VC90.CRT.manifest)
1480+ ;
1481+ ; See http://mixxx.org/wiki/doku.php/build_windows_installer for full details.
1482+
1483+ !ifdef x64 ; x64 versions
1484+ File ..\mixxx-win64lib\msvcr*.dll
1485+ File ..\mixxx-win64lib\msvcp*.dll
1486+ File /nonfatal ..\mixxx-win64lib\msvcm*.dll
1487+ File ..\mixxx-win64lib\Microsoft.VC*.CRT.manifest
1488+ !else ; x86 versions
1489+ File ..\mixxx-winlib\msvcr*.dll
1490+ File ..\mixxx-winlib\msvcp*.dll
1491+ File /nonfatal ..\mixxx-winlib\msvcm*.dll
1492+ File ..\mixxx-winlib\Microsoft.VC*.CRT.manifest
1493+ !endif
1494+
1495+ ; And documentation, licence etc.
1496+ File "Mixxx-Manual.pdf"
1497+ File "LICENSE"
1498+ File "README"
1499+ File "COPYING"
1500+
1501+ SetOutPath $INSTDIR\midi
1502+ File /r /x ".svn" /x ".bzr" dist\midi\*.*
1503+
1504+ ;Disabled for initial 1.6.0 release
1505+ ;SetOutPath $INSTDIR\promo
1506+ ;File "dist\promo\*"
1507+
1508+ SetOutPath $INSTDIR\keyboard
1509+ File "dist\keyboard\Standard.kbd.cfg"
1510+ File "dist\keyboard\Old.kbd.cfg"
1511+
1512+ SetOutPath "$INSTDIR\skins"
1513+ File /r /x ".svn" /x ".bzr" dist\skins\*.*
1514+
1515+ ; Write the installation path into the registry
1516+ ;WriteRegStr HKLM SOFTWARE\NSIS_Mixxx "Install_Dir" "$INSTDIR"
1517+ WriteRegStr HKLM "${PRODUCT_DIR_REGKEY}" "" "$INSTDIR\Mixxx.exe"
1518+
1519+ ; Write the uninstall keys for Windows
1520+ WriteUninstaller "$INSTDIR\uninst.exe"
1521+ WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayName" "$(^Name)"
1522+ WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\uninst.exe"
1523+ WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayIcon" "$INSTDIR\Mixxx.exe"
1524+ WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_VERSION}"
1525+ WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "URLInfoAbout" "${PRODUCT_WEB_SITE}"
1526+ WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}"
1527+ WriteRegDWORD ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "NoModify" 1
1528+ WriteRegDWORD ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "NoRepair" 1
1529+
1530+SectionEnd
1531+
1532+; Optional section (can be disabled by the user)
1533+Section "Start Menu Shortcuts" SecStartMenu
1534+
1535+ CreateDirectory "$SMPROGRAMS\Mixxx"
1536+ SetOutPath $INSTDIR
1537+ CreateShortCut "$SMPROGRAMS\Mixxx\Mixxx.lnk" "$INSTDIR\mixxx.exe" "" "$INSTDIR\mixxx.exe" 0
1538+ CreateShortCut "$SMPROGRAMS\Mixxx\Manual.lnk" "$INSTDIR\Mixxx-Manual.pdf" "" "$INSTDIR\Mixxx-Manual.pdf" 0
1539+ CreateShortCut "$SMPROGRAMS\Mixxx\Uninstall.lnk" "$INSTDIR\uninst.exe" "" "$INSTDIR\uninst.exe" 0
1540+
1541+SectionEnd
1542+
1543+; Optional section (can be disabled by the user)
1544+Section "Desktop Shortcut" SecDesktop
1545+
1546+ SetOutPath $INSTDIR
1547+ CreateShortCut "$DESKTOP\Mixxx.lnk" "$INSTDIR\mixxx.exe" "" "$INSTDIR\mixxx.exe" 0
1548+
1549+SectionEnd
1550+
1551+;--------------------------------
1552+;Descriptions
1553+
1554+ ;Language strings
1555+ LangString DESC_SecMixxx ${LANG_ENGLISH} "Mixxx software."
1556+ LangString DESC_SecStartMenu ${LANG_ENGLISH} "Start menu shortcuts."
1557+ LangString DESC_SecDesktop ${LANG_ENGLISH} "Desktop shortcut."
1558+
1559+ ;Assign language strings to sections
1560+ !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
1561+ !insertmacro MUI_DESCRIPTION_TEXT ${SecMixxx} $(DESC_SecMixxx)
1562+ !insertmacro MUI_DESCRIPTION_TEXT ${SecStartMenu} $(DESC_SecStartMenu)
1563+ !insertmacro MUI_DESCRIPTION_TEXT ${SecDesktop} $(DESC_SecDesktop)
1564+ !insertmacro MUI_FUNCTION_DESCRIPTION_END
1565+
1566+
1567+;--------------------------------
1568+
1569+; Uninstaller
1570+
1571+Function un.onUninstSuccess
1572+ HideWindow
1573+ MessageBox MB_ICONINFORMATION|MB_OK "$(^Name) was successfully removed from your computer."
1574+FunctionEnd
1575+
1576+Function un.onInit
1577+!insertmacro MUI_UNGETLANGUAGE
1578+ MessageBox MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2 "Are you sure you want to completely remove $(^Name) and all of its components?" IDYES +2
1579+ Abort
1580+FunctionEnd
1581+
1582+Section "Uninstall"
1583+
1584+ ; Remove files and uninstaller
1585+ Delete $INSTDIR\mixxx.exe
1586+ Delete $INSTDIR\mixxx.log
1587+ Delete $INSTDIR\*.dll
1588+ Delete $INSTDIR\uninst.exe
1589+ Delete $INSTDIR\Mixxx-Manual.pdf
1590+ Delete $INSTDIR\LICENSE
1591+ Delete $INSTDIR\README
1592+ Delete $INSTDIR\COPYING
1593+
1594+ ; Remove skins, keyboard, midi defs
1595+ Delete $INSTDIR\skins\outline\*.*
1596+ Delete $INSTDIR\skins\outlineClose\*.*
1597+ Delete $INSTDIR\skins\outlineNetbook\*.*
1598+ Delete $INSTDIR\skins\outlineSmall\*.*
1599+ Delete $INSTDIR\skins\outlineMini\*.*
1600+ Delete "$INSTDIR\skins\Collusion (1280)\*.*"
1601+ Delete "$INSTDIR\skins\Collusion (1280-WS)\*.*"
1602+ Delete $INSTDIR\skins\hercules\*.*
1603+ Delete $INSTDIR\skins\nCut\*.*
1604+ Delete $INSTDIR\skins\traditional\*.*
1605+ Delete $INSTDIR\skins\*.*
1606+ Delete $INSTDIR\keyboard\*.*
1607+ Delete $INSTDIR\midi\*.*
1608+ ;Delete $INSTDIR\promo\*.*
1609+ RMDir "$INSTDIR\skins\outline"
1610+ RMDir "$INSTDIR\skins\outlineNetbook"
1611+ RMDir "$INSTDIR\skins\outlineClose"
1612+ RMDir "$INSTDIR\skins\outlineSmall"
1613+ RMDir "$INSTDIR\skins\outlineMini"
1614+ RMDir "$INSTDIR\skins\Collusion (1280)"
1615+ RMDir "$INSTDIR\skins\Collusion (1280-WS)"
1616+ RMDir "$INSTDIR\skins\hercules"
1617+ RMDir "$INSTDIR\skins\nCut"
1618+ RMDir "$INSTDIR\skins\traditional"
1619+ RMDir "$INSTDIR\skins"
1620+ RMDir "$INSTDIR\midi"
1621+ RMDir "$INSTDIR\keyboard"
1622+ ;RMDir "$INSTDIR\promo"
1623+
1624+
1625+ ; Remove shortcuts, if any
1626+ Delete "$SMPROGRAMS\Mixxx\*.*"
1627+ Delete "$DESKTOP\Mixxx.lnk"
1628+
1629+ ; Remove directories used
1630+ RMDir "$SMPROGRAMS\Mixxx"
1631+ RMDir "$INSTDIR"
1632+
1633+ ; Remove registry keys
1634+ DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}"
1635+ ;DeleteRegKey HKLM SOFTWARE\NSIS_Mixxx
1636+ DeleteRegKey HKLM "${PRODUCT_DIR_REGKEY}"
1637+ SetAutoClose true
1638+
1639+SectionEnd
1640
1641=== modified file 'mixxx/src/SConscript'
1642--- mixxx/src/SConscript 2009-11-10 00:33:12 +0000
1643+++ mixxx/src/SConscript 2009-11-10 00:33:16 +0000
1644@@ -1,4 +1,5 @@
1645 #!/usr/bin/env python
1646+# -*- coding: utf-8 -*-
1647 import os
1648 import sys
1649 import SCons
1650@@ -216,7 +217,6 @@
1651 vars.Add('script', 'Set to 1 to enable MixxxScript/QtScript Studio support.', 0)
1652 vars.Add('midiscript', 'Set to 1 to enable MIDI Scripting support.', 1)
1653 vars.Add('tonal', 'Set to 1 to enable tonal analysis', 0)
1654-vars.Add('portmidi', 'Set to 1 to enable PortMidi unified MIDI backend', 0)
1655 vars.Add('m4a','Set to 1 to enable support for M4A audio (Apple non-drm''d music format)', 1)
1656 vars.Add('qdebug', 'Set to 1 to enable verbose console debug output.', 1)
1657 vars.Add('test', 'Set to 1 to build Mixxx test fixtures.', 0)
1658@@ -326,20 +326,19 @@
1659 analyserbpm.cpp
1660 analyserwaveform.cpp
1661
1662+ midi/midimapping.cpp
1663+ midi/midiinputmappingtablemodel.cpp
1664+ midi/midioutputmappingtablemodel.cpp
1665+ midi/midichanneldelegate.cpp
1666+ midi/midistatusdelegate.cpp
1667+ midi/midinodelegate.cpp
1668+ midi/midioptiondelegate.cpp
1669+ midi/midimessage.cpp
1670+ midi/midiledhandler.cpp
1671+
1672 main.cpp
1673- midiobject.cpp
1674- midimapping.cpp
1675- midiobjectnull.cpp
1676- mididevicehandler.cpp
1677- midiinputmappingtablemodel.cpp
1678- midioutputmappingtablemodel.cpp
1679- midichanneldelegate.cpp
1680- midistatusdelegate.cpp
1681- midinodelegate.cpp
1682- midioptiondelegate.cpp
1683 controlgroupdelegate.cpp
1684 controlvaluedelegate.cpp
1685- midimessage.cpp
1686 mixxxcontrol.cpp
1687 mixxx.cpp
1688 mixxxview.cpp
1689@@ -411,7 +410,6 @@
1690 imgcolor.cpp
1691
1692 trackinfoobject.cpp
1693- midiledhandler.cpp
1694 sounddevice.cpp
1695 soundmanager.cpp
1696 sounddeviceportaudio.cpp
1697@@ -433,17 +431,6 @@
1698 #elif 'win' in platform:
1699 # sources += Split("""powermatewin.cpp mousewin.cpp """)
1700
1701-#Compile platform specific MIDI support
1702-# Linux moved to the flag parsing area since it depends on the rawmidi flag
1703-if 'win' in platform:
1704- sources += Split("""midiobjectwin.cpp """) #Windows MIDI support
1705- env.Append(CXXFLAGS = '-D__WINMIDI__')
1706-elif platform == 'osx':
1707- sources += Split("""midiobjectcoremidi.cpp """) #CoreMidi support for OS X
1708- env.Append(CXXFLAGS = '-D__COREMIDI__')
1709-elif platform == 'bsd':
1710- print 'Warning: Mixxx has no support for BSD midi (yet).' #uuuuhhhh not a very good solution
1711-
1712 #Set up the library path on Windows:
1713 if platform == 'win64':
1714 env.Append(CPPPATH='#/../mixxx-win64lib') #If you add more directories, separate them with a semicolon (;)
1715@@ -456,6 +443,7 @@
1716 if 'win' in platform:
1717 env.Append(CPPPATH='../../lib/ladspa') #If you add more directories, separate them with a semicolon (;)
1718 env.Append(LINKFLAGS = ['/nodefaultlib:libc.lib', '/nodefaultlib:libcd.lib', '/entry:mainCRTStartup'])
1719+ env.Append(LIBS='advapi32') # needed for PortMIDI
1720 #'/subsystem:windows',
1721
1722 if platform == 'bsd':
1723@@ -480,21 +468,6 @@
1724 #if not env.GetOption('clean') and not SCons.Util.containsAny(os.sys.argv, ['-h', '--help']):
1725 conf = Configure(env, custom_tests = { 'CheckForPKGConfig' : CheckForPKGConfig, 'CheckForPKG' : CheckForPKG })
1726
1727-
1728-#PortMidi backend support
1729-flags_portmidi = getFlags(env, 'portmidi', 0)
1730-if int(flags_portmidi):
1731- if not conf.CheckLib(['portmidi', 'libportmidi']):
1732- print "Did not find portmidi or it\'s development headers, exiting!"
1733- Exit(1)
1734- #if not conf.CheckLib(['porttime', 'libporttime']):
1735- # print "Did not find porttime or it\'s development headers, exiting!"
1736- # Exit(1)
1737- sources += Split("""midiobjectportmidi.cpp """);
1738- env.Append(CPPDEFINES = '__PORTMIDI__')
1739-
1740-
1741-
1742 #TODO: Add all of the other configure checks as custom_tests properly.
1743
1744 # On Posix default SCons.LIBPREFIX = 'lib', on Windows default SCons.LIBPREFIX = ''
1745@@ -566,6 +539,20 @@
1746 #Check if FFMPEG was enabled
1747 CheckFFMPEG(conf, sources)
1748
1749+#Check for PortTime
1750+if not conf.CheckLib(['porttime', 'libporttime']):
1751+ print "Did not find PortTime or it\'s development headers, exiting!"
1752+ Exit(1)
1753+
1754+#Check for PortMIDI
1755+if not conf.CheckLib(['portmidi', 'libportmidi']):
1756+ print "Did not find PortMidi or it\'s development headers, exiting!"
1757+ Exit(1)
1758+
1759+sources += Split("""midi/mididevice.cpp """);
1760+sources += Split("""midi/mididevicemanager.cpp """);
1761+sources += Split("""midi/midideviceportmidi.cpp """);
1762+env.Append(CPPDEFINES = '__PORTMIDI__')
1763
1764 #Platform-specific checks for Linux...
1765 if platform == 'linux':
1766@@ -611,7 +598,6 @@
1767 debug=False,
1768 )
1769
1770-
1771 #Check for libasound (libasound2?) (needed for ALSA seq MIDI support)
1772 if not conf.CheckLib('asound') and not conf.CheckForPKG('alsa', '1.0.10'):
1773 print "Did not find libasound (aka. libasound2), exiting!"
1774@@ -1092,7 +1078,7 @@
1775 print "MIDI Scripting... enabled"
1776
1777 build_flags += 'midiscript '
1778- sources += Split("""script/midiscriptengine.cpp""")
1779+ sources += Split("""midi/midiscriptengine.cpp""")
1780 env.Append(CPPPATH = '$QTDIR/include/QtScript')
1781 env.Append(CPPDEFINES = '__MIDISCRIPT__')
1782 else:
1783@@ -1215,18 +1201,6 @@
1784 env.Append(CPPDEFINES = 'QT_NO_DEBUG_OUTPUT')
1785 print "Debugging message output... disabled"
1786
1787-#ALSA API selection
1788-if platform == 'linux':
1789- flags_rawmidi = getFlags(env, 'rawmidi', 0)
1790- if int(flags_rawmidi):
1791- build_flags += 'rawmidi '
1792- sources += Split("""midiobjectalsa.cpp """) #ALSA RawMIDI support for Linux
1793- env.Append(CXXFLAGS = '-D__ALSAMIDI__')
1794- print "ALSA API... RawMIDI"
1795- else:
1796- sources += Split("""midiobjectalsaseq.cpp """) #ALSA Sequencer MIDI support for Linux
1797- env.Append(CXXFLAGS = '-D__ALSASEQMIDI__')
1798- print "ALSA API... Sequencer"
1799
1800 #Visual Studio 2005 hacks (MSVS Express Edition users shouldn't enable this)
1801 flags_msvshacks = getFlags(env, 'msvshacks', 0)
1802
1803=== modified file 'mixxx/src/controlbeat.h'
1804--- mixxx/src/controlbeat.h 2005-03-02 14:02:29 +0000
1805+++ mixxx/src/controlbeat.h 2009-11-10 00:33:16 +0000
1806@@ -20,6 +20,8 @@
1807
1808 #include "controlobject.h"
1809 #include "configobject.h"
1810+#include "defs.h"
1811+#include "midi/midimessage.h"
1812 #include <qdatetime.h>
1813
1814 /**
1815
1816=== modified file 'mixxx/src/controlgroupdelegate.cpp'
1817--- mixxx/src/controlgroupdelegate.cpp 2009-03-19 17:17:16 +0000
1818+++ mixxx/src/controlgroupdelegate.cpp 2009-11-10 00:33:16 +0000
1819@@ -8,7 +8,7 @@
1820 #include <QtCore>
1821 #include <QtGui>
1822 #include "configobject.h"
1823-#include "midiinputmappingtablemodel.h" //Need this to know MIDIINPUTTABLEINDEX_CONTROLOBJECTVALUE
1824+#include "midi/midiinputmappingtablemodel.h" //Need this to know MIDIINPUTTABLEINDEX_CONTROLOBJECTVALUE
1825 #include "controlvaluedelegate.h"
1826 #include "controlgroupdelegate.h"
1827
1828
1829=== modified file 'mixxx/src/controllogpotmeter.cpp'
1830--- mixxx/src/controllogpotmeter.cpp 2008-03-27 05:04:43 +0000
1831+++ mixxx/src/controllogpotmeter.cpp 2009-11-10 00:33:17 +0000
1832@@ -15,6 +15,7 @@
1833 * *
1834 ***************************************************************************/
1835
1836+#include <math.h>
1837 #include "controllogpotmeter.h"
1838
1839 /* -------- ------------------------------------------------------
1840
1841=== modified file 'mixxx/src/controlobject.h'
1842--- mixxx/src/controlobject.h 2009-07-17 05:06:48 +0000
1843+++ mixxx/src/controlobject.h 2009-11-10 00:33:17 +0000
1844@@ -24,8 +24,8 @@
1845 //#include <qaccel.h>
1846 #include <q3ptrqueue.h>
1847 #include <QMutex>
1848+#include "midi/midimessage.h"
1849 #include "configobject.h"
1850-#include "midiobject.h"
1851 #include "controlobjectthread.h"
1852
1853 class QWidget;
1854@@ -73,8 +73,8 @@
1855 static ControlObject *getControl(ConfigKey key);
1856 /** Used to add a pointer to the corresponding ControlObjectThread of this ControlObject */
1857 void addProxy(ControlObjectThread *pControlObjectThread);
1858- // To get rid of a proxy when the corresponding object is being deleted for example
1859- void removeProxy(ControlObjectThread *pControlObjectThread);
1860+ // To get rid of a proxy when the corresponding object is being deleted for example
1861+ void removeProxy(ControlObjectThread *pControlObjectThread);
1862 /** Update proxies, execep the one given a pointer to. Returns true if all updates
1863 * happend, otherwise false. */
1864 bool updateProxies(ControlObjectThread *pProxyNoUpdate=0);
1865
1866=== modified file 'mixxx/src/controlvaluedelegate.cpp'
1867--- mixxx/src/controlvaluedelegate.cpp 2009-04-30 12:54:20 +0000
1868+++ mixxx/src/controlvaluedelegate.cpp 2009-11-10 00:33:17 +0000
1869@@ -10,7 +10,7 @@
1870 #include "configobject.h"
1871 #include "controlgroupdelegate.h" //Need to get CONTROLGROUP_CHANNEL1_STRING, etc.
1872 #include "controlvaluedelegate.h"
1873-#include "midiinputmappingtablemodel.h" //Need this to know MIDIINPUTTABLEINDEX_CONTROLOBJECTGROUP
1874+#include "midi/midiinputmappingtablemodel.h" //Need this to know MIDIINPUTTABLEINDEX_CONTROLOBJECTGROUP
1875
1876 //Static var declarations
1877 QStringList ControlValueDelegate::m_channelControlValues;
1878
1879=== modified file 'mixxx/src/defs.h'
1880--- mixxx/src/defs.h 2009-11-10 00:33:14 +0000
1881+++ mixxx/src/defs.h 2009-11-10 00:33:17 +0000
1882@@ -17,11 +17,8 @@
1883 #ifndef DEFS_H
1884 #define DEFS_H
1885
1886-<<<<<<< TREE
1887-#define VERSION "Trunk"
1888-=======
1889 // Version number moved to defs_version.h to avoid lots of rebuilding
1890->>>>>>> MERGE-SOURCE
1891+
1892 #define MIXXX_PROMO_DIR "promo"
1893
1894 #include <math.h>
1895
1896=== modified file 'mixxx/src/dlgmidilearning.cpp'
1897--- mixxx/src/dlgmidilearning.cpp 2009-03-12 22:35:33 +0000
1898+++ mixxx/src/dlgmidilearning.cpp 2009-11-10 00:33:17 +0000
1899@@ -17,8 +17,8 @@
1900
1901 #include "dlgmidilearning.h"
1902 #include "mixxxcontrol.h"
1903-#include "midimessage.h"
1904-#include "midimapping.h"
1905+#include "midi/midimessage.h"
1906+#include "midi/midimapping.h"
1907
1908 DlgMidiLearning::DlgMidiLearning(QWidget * parent, MidiMapping* mapping) : QDialog(parent), Ui::DlgMidiLearning()
1909 {
1910
1911=== modified file 'mixxx/src/dlgmidilearning.h'
1912--- mixxx/src/dlgmidilearning.h 2009-03-12 22:35:33 +0000
1913+++ mixxx/src/dlgmidilearning.h 2009-11-10 00:33:17 +0000
1914@@ -23,7 +23,7 @@
1915 #include "ui_dlgmidilearning.h"
1916 #include "configobject.h"
1917 #include "mixxxcontrol.h"
1918-#include "midimessage.h"
1919+#include "midi/midimessage.h"
1920
1921 class MidiMapping;
1922
1923
1924=== modified file 'mixxx/src/dlgpreferences.cpp'
1925--- mixxx/src/dlgpreferences.cpp 2009-04-12 19:17:15 +0000
1926+++ mixxx/src/dlgpreferences.cpp 2009-11-10 00:33:17 +0000
1927@@ -36,7 +36,8 @@
1928 #include "dlgprefrecord.h"
1929 #include "mixxx.h"
1930 #include "track.h"
1931-#include "midiobject.h"
1932+#include "midi/mididevicemanager.h"
1933+#include "midi/mididevice.h"
1934 #include <QTabWidget>
1935
1936 #include <QTabBar>
1937@@ -46,10 +47,10 @@
1938
1939 DlgPreferences::DlgPreferences(MixxxApp * mixxx, MixxxView * view,
1940 SoundManager * soundman, Track *track,
1941- MidiObject * midi, ConfigObject<ConfigValue> * _config) : QDialog(), Ui::DlgPreferencesDlg()
1942+ MidiDeviceManager * midi, ConfigObject<ConfigValue> * _config) : QDialog(), Ui::DlgPreferencesDlg()
1943 {
1944 m_pMixxx = mixxx;
1945- m_pMidiObject = midi;
1946+ m_pMidiDeviceManager = midi;
1947
1948 setupUi(this);
1949 #if QT_VERSION >= 0x040400 //setHeaderHidden is a qt4.4 addition so having it in the .ui file breaks the build on OpenBSD4.4 (FIXME: revisit this when OpenBSD4.5 comes out?)
1950@@ -108,7 +109,7 @@
1951 // Connections
1952 connect(this, SIGNAL(showDlg()), this, SLOT(slotShow()));
1953 connect(this, SIGNAL(closeDlg()), this, SLOT(slotHide()));
1954- connect(m_pMidiObject, SIGNAL(devicesChanged()), this, SLOT(rescanMidi()));
1955+ connect(m_pMidiDeviceManager, SIGNAL(devicesChanged()), this, SLOT(rescanMidi()));
1956
1957 connect(this, SIGNAL(showDlg()), wsound, SLOT(slotUpdate()));
1958 connect(this, SIGNAL(showDlg()), wplaylist, SLOT(slotUpdate()));
1959@@ -158,7 +159,7 @@
1960 }
1961
1962 void DlgPreferences::createIcons()
1963-{
1964+{
1965 m_pSoundButton = new QTreeWidgetItem(contentsTreeWidget, QTreeWidgetItem::Type);
1966 m_pSoundButton->setIcon(0, QIcon(":/images/preferences/soundhardware.png"));
1967 m_pSoundButton->setText(0, tr("Sound Hardware"));
1968@@ -191,7 +192,7 @@
1969 m_pPlaylistButton->setTextAlignment(0, Qt::AlignLeft | Qt::AlignVCenter);
1970 m_pPlaylistButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
1971
1972- m_pControlsButton = new QTreeWidgetItem(contentsTreeWidget, QTreeWidgetItem::Type);
1973+ m_pControlsButton = new QTreeWidgetItem(contentsTreeWidget, QTreeWidgetItem::Type);
1974 m_pControlsButton->setIcon(0, QIcon(":/images/preferences/interface.png"));
1975 m_pControlsButton->setText(0, tr("Interface"));
1976 m_pControlsButton->setTextAlignment(0, Qt::AlignLeft | Qt::AlignVCenter);
1977@@ -248,66 +249,66 @@
1978 if (!current)
1979 current = previous;
1980
1981- if (current == m_pSoundButton)
1982- pagesWidget->setCurrentWidget(wsound);
1983- else if (current == m_pPlaylistButton)
1984- pagesWidget->setCurrentWidget(wplaylist);
1985- else if (current == m_pControlsButton)
1986- pagesWidget->setCurrentWidget(wcontrols);
1987- else if (current == m_pEqButton)
1988- pagesWidget->setCurrentWidget(weq);
1989- else if (current == m_pCrossfaderButton)
1990- pagesWidget->setCurrentWidget(wcrossfader);
1991- else if (current == m_pRecordingButton)
1992- pagesWidget->setCurrentWidget(wrecord);
1993- else if (current == m_pBPMdetectButton)
1994- pagesWidget->setCurrentWidget(wbpm);
1995+ if (current == m_pSoundButton)
1996+ pagesWidget->setCurrentWidget(wsound);
1997+ else if (current == m_pPlaylistButton)
1998+ pagesWidget->setCurrentWidget(wplaylist);
1999+ else if (current == m_pControlsButton)
2000+ pagesWidget->setCurrentWidget(wcontrols);
2001+ else if (current == m_pEqButton)
2002+ pagesWidget->setCurrentWidget(weq);
2003+ else if (current == m_pCrossfaderButton)
2004+ pagesWidget->setCurrentWidget(wcrossfader);
2005+ else if (current == m_pRecordingButton)
2006+ pagesWidget->setCurrentWidget(wrecord);
2007+ else if (current == m_pBPMdetectButton)
2008+ pagesWidget->setCurrentWidget(wbpm);
2009 #ifdef __VINYLCONTROL__
2010- else if (current == m_pVinylControlButton)
2011- pagesWidget->setCurrentWidget(wvinylcontrol);
2012+ else if (current == m_pVinylControlButton)
2013+ pagesWidget->setCurrentWidget(wvinylcontrol);
2014 #endif
2015 #ifdef __SHOUTCAST__
2016- else if (current == m_pShoutcastButton)
2017- pagesWidget->setCurrentWidget(wshoutcast);
2018+ else if (current == m_pShoutcastButton)
2019+ pagesWidget->setCurrentWidget(wshoutcast);
2020 #endif
2021
2022- //Handle selection of midi device items
2023- else if (m_midiBindingsButtons.indexOf(current) >= 0)
2024- {
2025- int index = m_midiBindingsButtons.indexOf(current);
2026- pagesWidget->setCurrentWidget(wmidiBindingsForDevice.value(index));
2027- //Manually fire this slot since it doesn't work right...
2028- wmidiBindingsForDevice.value(index)->slotUpdate();
2029- }
2030-
2031- //If the root "MIDI Device" item is clicked, select the first MIDI device instead.
2032- //If there is no first MIDI device, display a page that says so (just so we don't not change the page)
2033- else if (current == m_pMIDITreeItem)
2034- {
2035- if (wmidiBindingsForDevice.count() > 0)
2036- {
2037- //Expand the MIDI subtree
2038- contentsTreeWidget->setItemExpanded(m_pMIDITreeItem, true);
2039-
2040- /*
2041- * FIXME: None of the following works right, for some reason. - Albert Feb 9/09
2042- */
2043-
2044- //Select the first MIDI device
2045- //contentsTreeWidget->setItemSelected(m_pMIDITreeItem, false);
2046- /*
2047- foreach(QTreeWidgetItem* item, contentsTreeWidget->selectedItems())
2048- {
2049- contentsTreeWidget->setItemSelected(item, false);
2050- }*/
2051- //contentsTreeWidget->setItemSelected(m_midiBindingsButtons.value(0), true);
2052-
2053- }
2054- else
2055- {
2056- pagesWidget->setCurrentWidget(wNoMidi);
2057- }
2058- }
2059+ //Handle selection of midi device items
2060+ else if (m_midiBindingsButtons.indexOf(current) >= 0)
2061+ {
2062+ int index = m_midiBindingsButtons.indexOf(current);
2063+ pagesWidget->setCurrentWidget(wmidiBindingsForDevice.value(index));
2064+ //Manually fire this slot since it doesn't work right...
2065+ wmidiBindingsForDevice.value(index)->slotUpdate();
2066+ }
2067+
2068+ //If the root "MIDI Device" item is clicked, select the first MIDI device instead.
2069+ //If there is no first MIDI device, display a page that says so (just so we don't not change the page)
2070+ else if (current == m_pMIDITreeItem)
2071+ {
2072+ if (wmidiBindingsForDevice.count() > 0)
2073+ {
2074+ //Expand the MIDI subtree
2075+ contentsTreeWidget->setItemExpanded(m_pMIDITreeItem, true);
2076+
2077+ /*
2078+ * FIXME: None of the following works right, for some reason. - Albert Feb 9/09
2079+ */
2080+
2081+ //Select the first MIDI device
2082+ //contentsTreeWidget->setItemSelected(m_pMIDITreeItem, false);
2083+ /*
2084+ foreach(QTreeWidgetItem* item, contentsTreeWidget->selectedItems())
2085+ {
2086+ contentsTreeWidget->setItemSelected(item, false);
2087+ }*/
2088+ //contentsTreeWidget->setItemSelected(m_midiBindingsButtons.value(0), true);
2089+
2090+ }
2091+ else
2092+ {
2093+ pagesWidget->setCurrentWidget(wNoMidi);
2094+ }
2095+ }
2096
2097 }
2098
2099@@ -315,7 +316,7 @@
2100 {
2101 #ifdef __VINYLCONTROL__
2102 pagesWidget->setCurrentWidget(wvinylcontrol);
2103- contentsTreeWidget->setCurrentItem(m_pVinylControlButton);
2104+ contentsTreeWidget->setCurrentItem(m_pVinylControlButton);
2105 #endif
2106 }
2107
2108@@ -372,34 +373,50 @@
2109
2110 void DlgPreferences::setupMidiWidgets()
2111 {
2112-
2113- //TODO: For each MIDI device, create a MIDI dialog and put a little link to it in the treepane on the left
2114- QList<QString>* deviceList = m_pMidiObject->getDeviceList();
2115- QListIterator<QString> it(*deviceList);
2116-
2117- while (it.hasNext())
2118- {
2119- QString curDeviceName = QString(it.next()); //make a copy of it.next() so that the original list getting freed doesn't kill us
2120- //qDebug() << "curDeviceName: " << curDeviceName;
2121- DlgPrefMidiBindings* midiDlg = new DlgPrefMidiBindings(this, *m_pMidiObject, curDeviceName, config);
2122- wmidiBindingsForDevice.append(midiDlg);
2123- pagesWidget->addWidget(midiDlg);
2124- connect(this, SIGNAL(showDlg()), midiDlg, SLOT(slotUpdate()));
2125- connect(buttonBox, SIGNAL(accepted()), midiDlg, SLOT(slotApply()));
2126-
2127- QTreeWidgetItem * midiBindingsButton = new QTreeWidgetItem(QTreeWidgetItem::Type);
2128- //qDebug() << curDeviceName << " QTreeWidgetItem point is " << midiBindingsButton;
2129- midiBindingsButton->setIcon(0, QIcon(":/images/preferences/controllers.png"));
2130- midiBindingsButton->setText(0, curDeviceName);
2131- midiBindingsButton->setTextAlignment(0, Qt::AlignLeft | Qt::AlignVCenter);
2132- midiBindingsButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
2133- m_pMIDITreeItem->addChild(midiBindingsButton);
2134- m_midiBindingsButtons.append(midiBindingsButton);
2135- }
2136+ //For each MIDI device, create a MIDI dialog and put a little link to it in the treepane on the left
2137+ QList<MidiDevice*> deviceList = m_pMidiDeviceManager->getDeviceList(false, true);
2138+ QListIterator<MidiDevice*> it(deviceList);
2139+
2140+ while (it.hasNext())
2141+ {
2142+ MidiDevice* currentDevice = it.next();
2143+ QString curDeviceName = currentDevice->getName();
2144+ //qDebug() << "curDeviceName: " << curDeviceName;
2145+ DlgPrefMidiBindings* midiDlg = new DlgPrefMidiBindings(this, currentDevice, m_pMidiDeviceManager, config);
2146+ wmidiBindingsForDevice.append(midiDlg);
2147+ pagesWidget->addWidget(midiDlg);
2148+ connect(this, SIGNAL(showDlg()), midiDlg, SLOT(slotUpdate()));
2149+ connect(buttonBox, SIGNAL(accepted()), midiDlg, SLOT(slotApply()));
2150+ connect(midiDlg, SIGNAL(deviceStateChanged(DlgPrefMidiBindings*,bool)), this, SLOT(slotHighlightDevice(DlgPrefMidiBindings*,bool)));
2151+
2152+ QTreeWidgetItem * midiBindingsButton = new QTreeWidgetItem(QTreeWidgetItem::Type);
2153+ //qDebug() << curDeviceName << " QTreeWidgetItem point is " << midiBindingsButton;
2154+ midiBindingsButton->setIcon(0, QIcon(":/images/preferences/controllers.png"));
2155+ midiBindingsButton->setText(0, curDeviceName);
2156+ midiBindingsButton->setTextAlignment(0, Qt::AlignLeft | Qt::AlignVCenter);
2157+ midiBindingsButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
2158+ m_pMIDITreeItem->addChild(midiBindingsButton);
2159+ m_midiBindingsButtons.append(midiBindingsButton);
2160+
2161+ // Set the font correctly
2162+ QFont temp = midiBindingsButton->font(0);
2163+ if (currentDevice->isOpen()) temp.setBold(true);
2164+ else temp.setBold(false);
2165+ midiBindingsButton->setFont(0,temp);
2166+ }
2167 }
2168
2169 void DlgPreferences::slotApply()
2170 {
2171+ m_pMidiDeviceManager->saveMappings();
2172 // m_pMixxx->grabKeyboard();
2173 }
2174
2175+void DlgPreferences::slotHighlightDevice(DlgPrefMidiBindings* dialog, bool enabled)
2176+{
2177+ QTreeWidgetItem * midiBindingsButton = m_midiBindingsButtons.at(wmidiBindingsForDevice.indexOf(dialog));
2178+ QFont temp = midiBindingsButton->font(0);
2179+ if (enabled) temp.setBold(true);
2180+ else temp.setBold(false);
2181+ midiBindingsButton->setFont(0,temp);
2182+}
2183\ No newline at end of file
2184
2185=== modified file 'mixxx/src/dlgpreferences.h'
2186--- mixxx/src/dlgpreferences.h 2009-03-02 02:48:16 +0000
2187+++ mixxx/src/dlgpreferences.h 2009-11-10 00:33:17 +0000
2188@@ -46,7 +46,7 @@
2189 class DlgPrefVinyl;
2190 class DlgPrefShoutcast;
2191 class PowerMate;
2192-class MidiObject;
2193+class MidiDeviceManager;
2194
2195 /**
2196 *@author Tue & Ken Haste Andersen
2197@@ -57,7 +57,7 @@
2198 Q_OBJECT
2199 public:
2200 DlgPreferences(MixxxApp *mixxx, MixxxView *view, SoundManager *soundman,
2201- Track *track, MidiObject * midi, ConfigObject<ConfigValue> *config);
2202+ Track *track, MidiDeviceManager* midi, ConfigObject<ConfigValue> *config);
2203 ~DlgPreferences();
2204 void createIcons();
2205 public slots:
2206@@ -67,6 +67,7 @@
2207 void slotApply();
2208 void changePage(QTreeWidgetItem *current, QTreeWidgetItem *previous);
2209 void showVinylControlPage();
2210+ void slotHighlightDevice(DlgPrefMidiBindings* dialog, bool enabled);
2211 signals:
2212 void closeDlg();
2213 void showDlg();
2214@@ -102,7 +103,7 @@
2215 ConfigObject<ConfigValue> *config;
2216 MixxxApp *m_pMixxx;
2217 Track* m_pTrack;
2218- MidiObject* m_pMidiObject;
2219+ MidiDeviceManager* m_pMidiDeviceManager;
2220 };
2221
2222 #endif
2223
2224=== modified file 'mixxx/src/dlgprefmidibindings.cpp'
2225--- mixxx/src/dlgprefmidibindings.cpp 2009-04-30 20:27:18 +0000
2226+++ mixxx/src/dlgprefmidibindings.cpp 2009-11-10 00:33:17 +0000
2227@@ -16,45 +16,44 @@
2228 ***************************************************************************/
2229 #include <QtGui>
2230 #include <QDebug>
2231-#include "midiinputmappingtablemodel.h"
2232-#include "midioutputmappingtablemodel.h"
2233-#include "midichanneldelegate.h"
2234-#include "midistatusdelegate.h"
2235-#include "midinodelegate.h"
2236-#include "midioptiondelegate.h"
2237+#include "midi/midiinputmappingtablemodel.h"
2238+#include "midi/midioutputmappingtablemodel.h"
2239+#include "midi/midichanneldelegate.h"
2240+#include "midi/midistatusdelegate.h"
2241+#include "midi/midinodelegate.h"
2242+#include "midi/midioptiondelegate.h"
2243 #include "controlgroupdelegate.h"
2244 #include "controlvaluedelegate.h"
2245 #include "dlgprefmidibindings.h"
2246+#include "midi/mididevice.h"
2247+#include "midi/mididevicemanager.h"
2248 #include "widget/wwidget.h"
2249 #include "configobject.h"
2250-#include "midimapping.h"
2251+#include "midi/midimapping.h"
2252
2253 #ifdef __MIDISCRIPT__
2254-#include "script/midiscriptengine.h"
2255+#include "midi/midiscriptengine.h"
2256 #endif
2257
2258-const QStringList options = (QStringList() << "Normal" << "Script-Binding" << "Invert" << "Rot64" << "Rot64Inv"
2259- << "Rot64Fast" << "Diff" << "Button" << "Switch" << "HercJog"
2260- << "Spread64" << "SelectKnob");
2261-
2262-QStringList controKeyOptionChoices;
2263-
2264-const QStringList outputTypeChoices = (QStringList() << "light");
2265-
2266-DlgPrefMidiBindings::DlgPrefMidiBindings(QWidget *parent, MidiObject &midi, QString deviceName,
2267- ConfigObject<ConfigValue> *pConfig) :
2268- QWidget(parent), Ui::DlgPrefMidiBindingsDlg(), m_rMidi(midi) {
2269+
2270+#define MIXXX_TEXT_NO_OUTPUT_DEVICE tr("None")
2271+
2272+DlgPrefMidiBindings::DlgPrefMidiBindings(QWidget *parent, MidiDevice* midiDevice,
2273+ MidiDeviceManager* midiDeviceManager,
2274+ ConfigObject<ConfigValue> *pConfig) :
2275+ QWidget(parent), Ui::DlgPrefMidiBindingsDlg() {
2276 setupUi(this);
2277 m_pConfig = pConfig;
2278- m_deviceName = deviceName;
2279+ m_pMidiDevice = midiDevice;
2280+ m_pMidiDeviceManager = midiDeviceManager;
2281
2282 m_pDlgMidiLearning = NULL;
2283
2284- labelDeviceName->setText(m_deviceName);
2285+ labelDeviceName->setText(m_pMidiDevice->getName());
2286
2287 //Tell the input mapping table widget which data model it should be viewing
2288 //(note that m_pInputMappingTableView is defined in the .ui file!)
2289- m_pInputMappingTableView->setModel((QAbstractItemModel*)m_rMidi.getMidiMapping()->getMidiInputMappingTableModel());
2290+ m_pInputMappingTableView->setModel((QAbstractItemModel*)m_pMidiDevice->getMidiMapping()->getMidiInputMappingTableModel());
2291
2292 m_pInputMappingTableView->setSelectionBehavior(QAbstractItemView::SelectRows);
2293 m_pInputMappingTableView->setSelectionMode(QAbstractItemView::ContiguousSelection); //The model won't like ExtendedSelection, probably.
2294@@ -84,7 +83,7 @@
2295
2296 //Tell the output mapping table widget which data model it should be viewing
2297 //(note that m_pOutputMappingTableView is defined in the .ui file!)
2298- m_pOutputMappingTableView->setModel((QAbstractItemModel*)m_rMidi.getMidiMapping()->getMidiOutputMappingTableModel());
2299+ m_pOutputMappingTableView->setModel((QAbstractItemModel*)m_pMidiDevice->getMidiMapping()->getMidiOutputMappingTableModel());
2300 m_pOutputMappingTableView->setSelectionBehavior(QAbstractItemView::SelectRows);
2301 m_pOutputMappingTableView->setSelectionMode(QAbstractItemView::ContiguousSelection);
2302 m_pOutputMappingTableView->verticalHeader()->hide();
2303@@ -111,14 +110,15 @@
2304 connect(btnClearAllOutputBindings, SIGNAL(clicked()), this, SLOT(slotClearAllOutputBindings()));
2305 connect(btnRemoveOutputBinding, SIGNAL(clicked()), this, SLOT(slotRemoveOutputBinding()));
2306 connect(btnAddOutputBinding, SIGNAL(clicked()), this, SLOT(slotAddOutputBinding()));
2307-
2308- //Connect the activate button. One day this will be replaced with an "Enabled" checkbox.
2309- connect(btnActivateDevice, SIGNAL(clicked()), this, SLOT(slotEnableDevice()));
2310
2311 connect(comboBoxPreset, SIGNAL(activated(const QString&)), this, SLOT(slotLoadMidiMapping(const QString&)));
2312
2313 //Load the list of presets into the presets combobox.
2314 enumeratePresets();
2315+
2316+ //Initialize the output device combobox
2317+ enumerateOutputDevices();
2318+
2319 }
2320
2321 DlgPrefMidiBindings::~DlgPrefMidiBindings() {
2322@@ -130,6 +130,31 @@
2323 delete m_deleteMIDIInputRowAction;
2324 }
2325
2326+void DlgPrefMidiBindings::enumerateOutputDevices()
2327+{
2328+ comboBoxOutputDevice->clear();
2329+
2330+ comboBoxOutputDevice->addItem(MIXXX_TEXT_NO_OUTPUT_DEVICE);
2331+
2332+ //For each MIDI output device, insert an item into the output device combobox.
2333+ QList<MidiDevice*> deviceList = m_pMidiDeviceManager->getDeviceList(true, false);
2334+ QListIterator<MidiDevice*> it(deviceList);
2335+
2336+ while (it.hasNext())
2337+ {
2338+ MidiDevice* currentDevice = it.next();
2339+ QString curDeviceName = currentDevice->getName();
2340+ //qDebug() << "curDeviceName: " << curDeviceName;
2341+ comboBoxOutputDevice->addItem(curDeviceName);
2342+ }
2343+
2344+ //Assume autopairing was done and let's just show the output device combobox with the name
2345+ //of the input device selected for now...
2346+ QString currentOutputMidiDeviceName = m_pMidiDevice->getName();
2347+ comboBoxOutputDevice->setCurrentIndex(comboBoxOutputDevice->findText(currentOutputMidiDeviceName));
2348+
2349+}
2350+
2351 void DlgPrefMidiBindings::enumeratePresets()
2352 {
2353 QList<QString> presetsList;
2354@@ -157,12 +182,6 @@
2355 comboBoxPreset->addItems(presetsList);
2356 }
2357
2358-/* loadPreset(QString)
2359- * Asks MidiMapping to load a set of MIDI bindings from an XML file
2360- */
2361-void DlgPrefMidiBindings::loadPreset(QString path) {
2362- m_rMidi.getMidiMapping()->loadPreset(path);
2363-}
2364
2365
2366 /* slotUpdate()
2367@@ -171,34 +190,47 @@
2368 void DlgPrefMidiBindings::slotUpdate() {
2369
2370 //Check if the device that this dialog is for is already enabled...
2371- if (m_rMidi.getOpenDevice() == m_deviceName)
2372+ if (m_pMidiDevice->isOpen())
2373 {
2374- btnActivateDevice->setEnabled(false); //Disable activate button
2375+ chkEnabledDevice->setCheckState(Qt::Checked); //Check the "Enabled" box
2376 toolBox->setEnabled(true); //Enable MIDI in/out toolbox.
2377 groupBoxPresets->setEnabled(true); //Enable presets group box.
2378 }
2379 else {
2380- btnActivateDevice->setEnabled(true); //Enable activate button
2381+ chkEnabledDevice->setCheckState(Qt::Unchecked); //Uncheck the "Enabled" box
2382 toolBox->setEnabled(false); //Disable MIDI in/out toolbox.
2383 groupBoxPresets->setEnabled(false); //Disable presets group box.
2384 }
2385+
2386+ //Connect the "Enabled" checkbox after the checkbox state is set
2387+ connect(chkEnabledDevice, SIGNAL(stateChanged(int)), this, SLOT(slotDeviceState(int)));
2388 }
2389
2390 /* slotApply()
2391 * Called when the OK button is pressed.
2392 */
2393 void DlgPrefMidiBindings::slotApply() {
2394- /* User has pressed OK, so write the controls to the DOM, reload the MIDI
2395- * bindings, and save the default XML file. */
2396- m_rMidi.getMidiMapping()->savePreset(); // use default bindings path
2397- m_rMidi.getMidiMapping()->applyPreset();
2398- m_rMidi.disableMidiLearn();
2399+ /* User has pressed OK, so enable or disable the device, write the controls to the DOM, and reload the MIDI
2400+ * bindings. */
2401+ m_pMidiDevice->disableMidiLearn();
2402+ if (chkEnabledDevice->isChecked()) {
2403+ enableDevice();
2404+ m_pMidiDevice->getMidiMapping()->applyPreset();
2405+
2406+ //FIXME: We need some logic like this to make changing the output device work.
2407+ // See MidiDeviceManager::associateInputAndOutputDevices() for more info...
2408+ /*
2409+ if (comboBoxOutputDevice->currentText() != MIXXX_TEXT_NO_OUTPUT_DEVICE)
2410+ m_pMidiDeviceManager->associateInputAndOutputDevices(m_pMidiDevice, comboBoxOutputDevice->currentText());
2411+ */
2412+ }
2413+ else disableDevice();
2414 }
2415
2416 void DlgPrefMidiBindings::slotShowMidiLearnDialog() {
2417 //Note that DlgMidiLearning is set to delete itself on
2418 //close using the Qt::WA_DeleteOnClose attribute (so this "new" doesn't leak memory)
2419- m_pDlgMidiLearning = new DlgMidiLearning(this, m_rMidi.getMidiMapping());
2420+ m_pDlgMidiLearning = new DlgMidiLearning(this, m_pMidiDevice->getMidiMapping());
2421 m_pDlgMidiLearning->show();
2422 }
2423
2424@@ -211,7 +243,7 @@
2425 return;
2426
2427 //Ask for confirmation if the MIDI tables aren't empty...
2428- MidiMapping* mapping = m_rMidi.getMidiMapping();
2429+ MidiMapping* mapping = m_pMidiDevice->getMidiMapping();
2430 if (mapping->numInputMidiMessages() > 0 ||
2431 mapping->numOutputMixxxControls() > 0)
2432 {
2433@@ -220,19 +252,16 @@
2434 tr("Are you sure you'd like to load the " + name + " mapping?\n"
2435 "This will overwrite your existing MIDI mapping."),
2436 QMessageBox::Yes | QMessageBox::No);
2437-
2438+
2439 if (result == QMessageBox::No) {
2440 //Select the "..." item again in the combobox.
2441 comboBoxPreset->setCurrentIndex(0);
2442- return;
2443+ return;
2444 }
2445 }
2446
2447 QString filename = m_pConfig->getConfigPath().append("midi/") + name + MIDI_MAPPING_EXTENSION;
2448- if (!filename.isNull()) {
2449- loadPreset(filename);
2450- m_rMidi.getMidiMapping()->applyPreset();
2451- }
2452+ if (!filename.isNull()) m_pMidiDevice->getMidiMapping()->loadPreset(filename, true); // It's applied on prefs close
2453 m_pInputMappingTableView->update();
2454
2455 //Select the "..." item again in the combobox.
2456@@ -246,20 +275,37 @@
2457 QString fileName = QFileDialog::getSaveFileName(this,
2458 "Export Mixxx MIDI Bindings", m_pConfig->getConfigPath().append("midi/"),
2459 "Preset Files (*.midi.xml)");
2460- if (!fileName.isNull()) m_rMidi.getMidiMapping()->savePreset(fileName);
2461-}
2462-
2463-void DlgPrefMidiBindings::slotEnableDevice()
2464-{
2465- //Just tell MidiObject to close the old device and open this device
2466- m_rMidi.devClose();
2467- m_rMidi.devOpen(m_deviceName);
2468- m_pConfig->set(ConfigKey("[Midi]","Device"), m_deviceName);
2469- btnActivateDevice->setEnabled(false);
2470- toolBox->setEnabled(true); //Enable MIDI in/out toolbox.
2471- groupBoxPresets->setEnabled(true); //Enable presets group box.
2472-
2473- //TODO: Should probably check if devOpen() actually succeeded.
2474+ if (!fileName.isNull()) m_pMidiDevice->getMidiMapping()->savePreset(fileName);
2475+}
2476+
2477+void DlgPrefMidiBindings::slotDeviceState(int state) {
2478+ if (state == Qt::Checked) {
2479+ toolBox->setEnabled(true); //Enable MIDI in/out toolbox.
2480+ groupBoxPresets->setEnabled(true); //Enable presets group box.
2481+ emit deviceStateChanged(this,true); // Set tree item text to bold
2482+ }
2483+ else {
2484+ toolBox->setEnabled(false); //Disable MIDI in/out toolbox.
2485+ groupBoxPresets->setEnabled(false); //Disable presets group box.
2486+ emit deviceStateChanged(this,false); // Set tree item text to not bold
2487+ }
2488+}
2489+
2490+void DlgPrefMidiBindings::enableDevice()
2491+{
2492+ m_pMidiDevice->close();
2493+ m_pMidiDevice->open();
2494+ m_pConfig->set(ConfigKey("[Midi]", m_pMidiDevice->getName().replace(" ", "_")), 1);
2495+
2496+ //TODO: Should probably check if open() actually succeeded.
2497+}
2498+
2499+void DlgPrefMidiBindings::disableDevice()
2500+{
2501+ m_pMidiDevice->close();
2502+ m_pConfig->set(ConfigKey("[Midi]", m_pMidiDevice->getName().replace(" ", "_")), 0);
2503+
2504+ //TODO: Should probably check if close() actually succeeded.
2505 }
2506
2507 void DlgPrefMidiBindings::slotAddInputBinding()
2508@@ -296,40 +342,40 @@
2509 MixxxControl mixxxControl(controlGroup, controlValue);
2510 MidiMessage message;
2511
2512- while (m_rMidi.getMidiMapping()->isMidiMessageMapped(message))
2513+ while (m_pMidiDevice->getMidiMapping()->isMidiMessageMapped(message))
2514 {
2515 message.setMidiNo(message.getMidiNo() + 1);
2516 if (message.getMidiNo() >= 127) //If the table is full, then overwrite something...
2517 break;
2518 }
2519- m_rMidi.getMidiMapping()->setInputMidiMapping(message, mixxxControl);
2520+ m_pMidiDevice->getMidiMapping()->setInputMidiMapping(message, mixxxControl);
2521 }
2522
2523 void DlgPrefMidiBindings::slotRemoveInputBinding()
2524 {
2525- QModelIndexList selectedIndices = m_pInputMappingTableView->selectionModel()->selectedRows();
2526- if (selectedIndices.size() > 0)
2527- {
2528- MidiInputMappingTableModel* tableModel = dynamic_cast<MidiInputMappingTableModel*>(m_pInputMappingTableView->model());
2529- if (tableModel) {
2530-
2531- QModelIndex curIndex;
2532- //The model indices are sorted so that we remove the rows from the table
2533+ QModelIndexList selectedIndices = m_pInputMappingTableView->selectionModel()->selectedRows();
2534+ if (selectedIndices.size() > 0)
2535+ {
2536+ MidiInputMappingTableModel* tableModel = dynamic_cast<MidiInputMappingTableModel*>(m_pInputMappingTableView->model());
2537+ if (tableModel) {
2538+
2539+ QModelIndex curIndex;
2540+ //The model indices are sorted so that we remove the rows from the table
2541 //in ascending order. This is necessary because if row A is above row B in
2542 //the table, and you remove row A, the model index for row B will change.
2543 //Sorting the indices first means we don't have to worry about this.
2544 qSort(selectedIndices);
2545
2546 //Going through the model indices in descending order (see above comment for explanation).
2547- QListIterator<QModelIndex> it(selectedIndices);
2548- it.toBack();
2549- while (it.hasPrevious())
2550- {
2551- curIndex = it.previous();
2552- tableModel->removeRow(curIndex.row());
2553- }
2554- }
2555- }
2556+ QListIterator<QModelIndex> it(selectedIndices);
2557+ it.toBack();
2558+ while (it.hasPrevious())
2559+ {
2560+ curIndex = it.previous();
2561+ tableModel->removeRow(curIndex.row());
2562+ }
2563+ }
2564+ }
2565 }
2566
2567 void DlgPrefMidiBindings::slotClearAllInputBindings() {
2568@@ -349,35 +395,35 @@
2569 void DlgPrefMidiBindings::slotAddOutputBinding() {
2570 qDebug() << "STUB: DlgPrefMidiBindings::slotAddOutputBinding()";
2571
2572- m_rMidi.getMidiMapping()->setOutputMidiMapping(MixxxControl(), MidiMessage());
2573+ m_pMidiDevice->getMidiMapping()->setOutputMidiMapping(MixxxControl(), MidiMessage());
2574 }
2575
2576 void DlgPrefMidiBindings::slotRemoveOutputBinding()
2577 {
2578- QModelIndexList selectedIndices = m_pOutputMappingTableView->selectionModel()->selectedRows();
2579- if (selectedIndices.size() > 0)
2580- {
2581- MidiOutputMappingTableModel* tableModel =
2582- dynamic_cast<MidiOutputMappingTableModel*>(m_pOutputMappingTableView->model());
2583- if (tableModel) {
2584- QModelIndex curIndex;
2585- //The model indices are sorted so that we remove the rows from the table
2586+ QModelIndexList selectedIndices = m_pOutputMappingTableView->selectionModel()->selectedRows();
2587+ if (selectedIndices.size() > 0)
2588+ {
2589+ MidiOutputMappingTableModel* tableModel =
2590+ dynamic_cast<MidiOutputMappingTableModel*>(m_pOutputMappingTableView->model());
2591+ if (tableModel) {
2592+ QModelIndex curIndex;
2593+ //The model indices are sorted so that we remove the rows from the table
2594 //in ascending order. This is necessary because if row A is above row B in
2595 //the table, and you remove row A, the model index for row B will change.
2596 //Sorting the indices first means we don't have to worry about this.
2597 //qSort(selectedIndices);
2598
2599 //Going through the model indices in descending order (see above comment for explanation).
2600- QListIterator<QModelIndex> it(selectedIndices);
2601- it.toBack();
2602- while (it.hasPrevious())
2603- {
2604- curIndex = it.previous();
2605- qDebug() << "Dlg: removing row" << curIndex.row();
2606- tableModel->removeRow(curIndex.row());
2607- }
2608- }
2609- }
2610+ QListIterator<QModelIndex> it(selectedIndices);
2611+ it.toBack();
2612+ while (it.hasPrevious())
2613+ {
2614+ curIndex = it.previous();
2615+ qDebug() << "Dlg: removing row" << curIndex.row();
2616+ tableModel->removeRow(curIndex.row());
2617+ }
2618+ }
2619+ }
2620 }
2621
2622 void DlgPrefMidiBindings::slotClearAllOutputBindings() {
2623
2624=== modified file 'mixxx/src/dlgprefmidibindings.h'
2625--- mixxx/src/dlgprefmidibindings.h 2009-04-11 20:16:51 +0000
2626+++ mixxx/src/dlgprefmidibindings.h 2009-11-10 00:33:17 +0000
2627@@ -21,7 +21,6 @@
2628 #include "ui_dlgprefmidibindingsdlg.h"
2629 #include "dlgmidilearning.h"
2630 #include "configobject.h"
2631-#include "midiobject.h"
2632
2633 //Forward declarations
2634 class MidiChannelDelegate;
2635@@ -30,11 +29,14 @@
2636 class MidiOptionDelegate;
2637 class ControlGroupDelegate;
2638 class ControlValueDelegate;
2639+class MidiDevice;
2640+class MidiDeviceManager;
2641
2642 class DlgPrefMidiBindings : public QWidget, public Ui::DlgPrefMidiBindingsDlg {
2643 Q_OBJECT
2644 public:
2645- DlgPrefMidiBindings(QWidget *parent, MidiObject &midi, QString deviceName,
2646+ DlgPrefMidiBindings(QWidget *parent, MidiDevice* midiDevice,
2647+ MidiDeviceManager* midiDeviceManager,
2648 ConfigObject<ConfigValue> *pConfig);
2649 ~DlgPrefMidiBindings();
2650
2651@@ -45,7 +47,7 @@
2652 void slotShowMidiLearnDialog();
2653 void slotLoadMidiMapping(const QString &name);
2654 void slotExportXML();
2655- void slotEnableDevice();
2656+ void slotDeviceState(int state);
2657
2658 //Input bindings
2659 void slotClearAllInputBindings();
2660@@ -56,15 +58,20 @@
2661 void slotAddOutputBinding();
2662 void slotClearAllOutputBindings();
2663 void slotRemoveOutputBinding();
2664+
2665+signals:
2666+ void deviceStateChanged(DlgPrefMidiBindings*, bool);
2667
2668 private:
2669 void setRowBackground(int row, QColor color);
2670- void loadPreset(QString path);
2671 void savePreset(QString path);
2672 void enumeratePresets();
2673+ void enumerateOutputDevices();
2674
2675+ void enableDevice();
2676+ void disableDevice();
2677+
2678 int currentGroupRow;
2679- MidiObject &m_rMidi;
2680 MidiChannelDelegate* m_pMidiChannelDelegate;
2681 MidiStatusDelegate* m_pMidiStatusDelegate;
2682 MidiNoDelegate* m_pMidiNoDelegate;
2683@@ -73,7 +80,8 @@
2684 ControlValueDelegate* m_pControlValueDelegate;
2685 QAction* m_deleteMIDIInputRowAction; /** Used for setting up the shortcut for delete button */
2686 ConfigObject<ConfigValue> *m_pConfig;
2687- QString m_deviceName;
2688+ MidiDevice* m_pMidiDevice;
2689+ MidiDeviceManager* m_pMidiDeviceManager;
2690 DlgMidiLearning* m_pDlgMidiLearning;
2691 };
2692
2693
2694=== modified file 'mixxx/src/dlgprefmidibindingsdlg.ui'
2695--- mixxx/src/dlgprefmidibindingsdlg.ui 2009-04-11 21:29:07 +0000
2696+++ mixxx/src/dlgprefmidibindingsdlg.ui 2009-11-10 00:33:17 +0000
2697@@ -1,7 +1,8 @@
2698-<ui version="4.0" >
2699+<?xml version="1.0" encoding="UTF-8"?>
2700+<ui version="4.0">
2701 <class>DlgPrefMidiBindingsDlg</class>
2702- <widget class="QWidget" name="DlgPrefMidiBindingsDlg" >
2703- <property name="geometry" >
2704+ <widget class="QWidget" name="DlgPrefMidiBindingsDlg">
2705+ <property name="geometry">
2706 <rect>
2707 <x>0</x>
2708 <y>0</y>
2709@@ -9,30 +10,30 @@
2710 <height>436</height>
2711 </rect>
2712 </property>
2713- <property name="windowTitle" >
2714+ <property name="windowTitle">
2715 <string>Dialog</string>
2716 </property>
2717- <layout class="QGridLayout" name="gridLayout_4" >
2718- <item row="0" column="0" >
2719- <widget class="QLabel" name="labelDeviceName" >
2720- <property name="font" >
2721+ <layout class="QGridLayout" name="gridLayout_4">
2722+ <item row="0" column="0">
2723+ <widget class="QLabel" name="labelDeviceName">
2724+ <property name="font">
2725 <font>
2726 <pointsize>14</pointsize>
2727 <weight>75</weight>
2728 <bold>true</bold>
2729 </font>
2730 </property>
2731- <property name="text" >
2732+ <property name="text">
2733 <string>Your Device Name</string>
2734 </property>
2735 </widget>
2736 </item>
2737- <item rowspan="2" row="0" column="1" >
2738- <spacer name="horizontalSpacer" >
2739- <property name="orientation" >
2740+ <item row="0" column="2" rowspan="2">
2741+ <spacer name="horizontalSpacer">
2742+ <property name="orientation">
2743 <enum>Qt::Horizontal</enum>
2744 </property>
2745- <property name="sizeHint" stdset="0" >
2746+ <property name="sizeHint" stdset="0">
2747 <size>
2748 <width>115</width>
2749 <height>20</height>
2750@@ -40,136 +41,150 @@
2751 </property>
2752 </spacer>
2753 </item>
2754- <item rowspan="2" row="0" column="2" >
2755- <widget class="QGroupBox" name="groupBoxPresets" >
2756- <property name="title" >
2757+ <item row="0" column="3" rowspan="2">
2758+ <widget class="QGroupBox" name="groupBoxPresets">
2759+ <property name="title">
2760 <string/>
2761 </property>
2762- <property name="flat" >
2763+ <property name="flat">
2764 <bool>true</bool>
2765 </property>
2766- <property name="checkable" >
2767+ <property name="checkable">
2768 <bool>false</bool>
2769 </property>
2770- <layout class="QGridLayout" name="gridLayout" >
2771- <item row="0" column="0" >
2772- <widget class="QLabel" name="label" >
2773- <property name="text" >
2774+ <layout class="QGridLayout" name="gridLayout">
2775+ <item row="1" column="1">
2776+ <widget class="QLabel" name="label">
2777+ <property name="text">
2778 <string>Load Preset:</string>
2779 </property>
2780- <property name="alignment" >
2781+ <property name="alignment">
2782 <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
2783 </property>
2784 </widget>
2785 </item>
2786- <item row="0" column="1" >
2787- <widget class="QComboBox" name="comboBoxPreset" >
2788- <property name="sizePolicy" >
2789- <sizepolicy vsizetype="Fixed" hsizetype="Fixed" >
2790+ <item row="1" column="2">
2791+ <widget class="QComboBox" name="comboBoxPreset">
2792+ <property name="sizePolicy">
2793+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
2794 <horstretch>0</horstretch>
2795 <verstretch>0</verstretch>
2796 </sizepolicy>
2797 </property>
2798 </widget>
2799 </item>
2800- <item row="0" column="2" >
2801- <widget class="QPushButton" name="btnExportXML" >
2802- <property name="styleSheet" >
2803- <string notr="true" />
2804+ <item row="1" column="3">
2805+ <widget class="QPushButton" name="btnExportXML">
2806+ <property name="styleSheet">
2807+ <string notr="true"/>
2808 </property>
2809- <property name="text" >
2810+ <property name="text">
2811 <string>Export</string>
2812 </property>
2813 </widget>
2814 </item>
2815+ <item row="2" column="2">
2816+ <widget class="QComboBox" name="comboBoxOutputDevice">
2817+ <property name="enabled">
2818+ <bool>false</bool>
2819+ </property>
2820+ </widget>
2821+ </item>
2822+ <item row="2" column="1">
2823+ <widget class="QLabel" name="label_2">
2824+ <property name="text">
2825+ <string>Output:</string>
2826+ </property>
2827+ </widget>
2828+ </item>
2829 </layout>
2830 </widget>
2831 </item>
2832- <item row="1" column="0" >
2833- <widget class="QPushButton" name="btnActivateDevice" >
2834- <property name="text" >
2835- <string>Activate</string>
2836+ <item row="1" column="0">
2837+ <widget class="QCheckBox" name="chkEnabledDevice">
2838+ <property name="text">
2839+ <string>Enabled</string>
2840 </property>
2841 </widget>
2842 </item>
2843- <item row="2" column="0" colspan="3" >
2844- <widget class="QToolBox" name="toolBox" >
2845- <property name="frameShape" >
2846+ <item row="2" column="0" colspan="4">
2847+ <widget class="QToolBox" name="toolBox">
2848+ <property name="frameShape">
2849 <enum>QFrame::NoFrame</enum>
2850 </property>
2851- <property name="currentIndex" >
2852+ <property name="currentIndex">
2853 <number>0</number>
2854 </property>
2855- <widget class="QWidget" name="page" >
2856- <property name="geometry" >
2857+ <widget class="QWidget" name="page">
2858+ <property name="geometry">
2859 <rect>
2860 <x>0</x>
2861 <y>0</y>
2862 <width>580</width>
2863- <height>287</height>
2864+ <height>252</height>
2865 </rect>
2866 </property>
2867- <attribute name="label" >
2868+ <attribute name="label">
2869 <string>MIDI Input</string>
2870 </attribute>
2871- <layout class="QGridLayout" name="gridLayout_2" >
2872- <item row="1" column="0" colspan="2" >
2873- <widget class="QTableView" name="m_pInputMappingTableView" />
2874+ <layout class="QGridLayout" name="gridLayout_2">
2875+ <item row="1" column="0" colspan="2">
2876+ <widget class="QTableView" name="m_pInputMappingTableView"/>
2877 </item>
2878- <item row="2" column="0" colspan="2" >
2879- <widget class="QGroupBox" name="groupBoxInputManagement" >
2880- <property name="minimumSize" >
2881+ <item row="2" column="0" colspan="2">
2882+ <widget class="QGroupBox" name="groupBoxInputManagement">
2883+ <property name="minimumSize">
2884 <size>
2885 <width>300</width>
2886 <height>0</height>
2887 </size>
2888 </property>
2889- <property name="title" >
2890+ <property name="title">
2891 <string>Controls</string>
2892 </property>
2893- <layout class="QHBoxLayout" name="horizontalLayout_2" >
2894+ <layout class="QHBoxLayout" name="horizontalLayout_2">
2895 <item>
2896- <widget class="QPushButton" name="btnAddInputBinding" >
2897- <property name="styleSheet" >
2898- <string notr="true" />
2899+ <widget class="QPushButton" name="btnAddInputBinding">
2900+ <property name="styleSheet">
2901+ <string notr="true"/>
2902 </property>
2903- <property name="text" >
2904+ <property name="text">
2905 <string>Add</string>
2906 </property>
2907 </widget>
2908 </item>
2909 <item>
2910- <widget class="QPushButton" name="btnRemoveInputBinding" >
2911- <property name="styleSheet" >
2912- <string notr="true" />
2913+ <widget class="QPushButton" name="btnRemoveInputBinding">
2914+ <property name="styleSheet">
2915+ <string notr="true"/>
2916 </property>
2917- <property name="text" >
2918+ <property name="text">
2919 <string>Remove</string>
2920 </property>
2921 </widget>
2922 </item>
2923 <item>
2924- <widget class="QPushButton" name="btnMidiLearnWizard" >
2925- <property name="styleSheet" >
2926- <string notr="true" />
2927+ <widget class="QPushButton" name="btnMidiLearnWizard">
2928+ <property name="styleSheet">
2929+ <string notr="true"/>
2930 </property>
2931- <property name="text" >
2932+ <property name="text">
2933 <string>MIDI Learning Wizard</string>
2934 </property>
2935- <property name="checkable" >
2936+ <property name="checkable">
2937 <bool>false</bool>
2938 </property>
2939- <property name="checked" >
2940+ <property name="checked">
2941 <bool>false</bool>
2942 </property>
2943 </widget>
2944 </item>
2945 <item>
2946- <spacer name="horizontalSpacer_3" >
2947- <property name="orientation" >
2948+ <spacer name="horizontalSpacer_3">
2949+ <property name="orientation">
2950 <enum>Qt::Horizontal</enum>
2951 </property>
2952- <property name="sizeHint" stdset="0" >
2953+ <property name="sizeHint" stdset="0">
2954 <size>
2955 <width>219</width>
2956 <height>20</height>
2957@@ -178,14 +193,14 @@
2958 </spacer>
2959 </item>
2960 <item>
2961- <widget class="QPushButton" name="btnClearAllInputBindings" >
2962- <property name="autoFillBackground" >
2963+ <widget class="QPushButton" name="btnClearAllInputBindings">
2964+ <property name="autoFillBackground">
2965 <bool>false</bool>
2966 </property>
2967- <property name="styleSheet" >
2968- <string notr="true" />
2969+ <property name="styleSheet">
2970+ <string notr="true"/>
2971 </property>
2972- <property name="text" >
2973+ <property name="text">
2974 <string>Clear All</string>
2975 </property>
2976 </widget>
2977@@ -195,55 +210,55 @@
2978 </item>
2979 </layout>
2980 </widget>
2981- <widget class="QWidget" name="page_2" >
2982- <property name="geometry" >
2983+ <widget class="QWidget" name="page_2">
2984+ <property name="geometry">
2985 <rect>
2986 <x>0</x>
2987 <y>0</y>
2988- <width>580</width>
2989- <height>287</height>
2990+ <width>317</width>
2991+ <height>174</height>
2992 </rect>
2993 </property>
2994- <attribute name="label" >
2995+ <attribute name="label">
2996 <string>MIDI Output</string>
2997 </attribute>
2998- <layout class="QGridLayout" name="gridLayout_3" >
2999- <item row="0" column="0" >
3000- <widget class="QTableView" name="m_pOutputMappingTableView" >
3001- <property name="enabled" >
3002+ <layout class="QGridLayout" name="gridLayout_3">
3003+ <item row="0" column="0">
3004+ <widget class="QTableView" name="m_pOutputMappingTableView">
3005+ <property name="enabled">
3006 <bool>true</bool>
3007 </property>
3008 </widget>
3009 </item>
3010- <item row="1" column="0" >
3011- <widget class="QGroupBox" name="groupBoxOutputs" >
3012- <property name="title" >
3013+ <item row="1" column="0">
3014+ <widget class="QGroupBox" name="groupBoxOutputs">
3015+ <property name="title">
3016 <string>Outputs</string>
3017 </property>
3018- <layout class="QHBoxLayout" name="horizontalLayout" >
3019+ <layout class="QHBoxLayout" name="horizontalLayout">
3020 <item>
3021- <widget class="QPushButton" name="btnAddOutputBinding" >
3022- <property name="enabled" >
3023+ <widget class="QPushButton" name="btnAddOutputBinding">
3024+ <property name="enabled">
3025 <bool>false</bool>
3026 </property>
3027- <property name="text" >
3028+ <property name="text">
3029 <string>Add</string>
3030 </property>
3031 </widget>
3032 </item>
3033 <item>
3034- <widget class="QPushButton" name="btnRemoveOutputBinding" >
3035- <property name="text" >
3036+ <widget class="QPushButton" name="btnRemoveOutputBinding">
3037+ <property name="text">
3038 <string>Remove</string>
3039 </property>
3040 </widget>
3041 </item>
3042 <item>
3043- <spacer name="horizontalSpacer_2" >
3044- <property name="orientation" >
3045+ <spacer name="horizontalSpacer_2">
3046+ <property name="orientation">
3047 <enum>Qt::Horizontal</enum>
3048 </property>
3049- <property name="sizeHint" stdset="0" >
3050+ <property name="sizeHint" stdset="0">
3051 <size>
3052 <width>219</width>
3053 <height>20</height>
3054@@ -252,8 +267,8 @@
3055 </spacer>
3056 </item>
3057 <item>
3058- <widget class="QPushButton" name="btnClearAllOutputBindings" >
3059- <property name="text" >
3060+ <widget class="QPushButton" name="btnClearAllOutputBindings">
3061+ <property name="text">
3062 <string>Clear All</string>
3063 </property>
3064 </widget>
3065
3066=== modified file 'mixxx/src/engine/enginesidechain.h'
3067--- mixxx/src/engine/enginesidechain.h 2009-01-24 04:39:32 +0000
3068+++ mixxx/src/engine/enginesidechain.h 2009-11-10 00:33:17 +0000
3069@@ -17,6 +17,7 @@
3070 #ifndef ENGINESIDECHAIN_H
3071 #define ENGINESIDECHAIN_H
3072
3073+#include <QtCore>
3074 #include "defs.h"
3075 #include "configobject.h"
3076 #include "controlobject.h"
3077
3078=== modified file 'mixxx/src/input.cpp'
3079--- mixxx/src/input.cpp 2009-02-10 23:42:19 +0000
3080+++ mixxx/src/input.cpp 2009-11-10 00:33:17 +0000
3081@@ -20,7 +20,6 @@
3082 #include "controlobject.h"
3083 #include "controlobjectthreadmain.h"
3084 #include "controlobjectthread.h"
3085-#include "midiobject.h"
3086 #include "mathstuff.h"
3087
3088 // TODO: Investigate the use of ControlObjectThread vs. ControlObjectThreadMain
3089
3090=== added directory 'mixxx/src/midi'
3091=== renamed file 'mixxx/src/midichanneldelegate.cpp' => 'mixxx/src/midi/midichanneldelegate.cpp'
3092=== renamed file 'mixxx/src/midichanneldelegate.h' => 'mixxx/src/midi/midichanneldelegate.h'
3093=== added file 'mixxx/src/midi/mididevice.cpp'
3094--- mixxx/src/midi/mididevice.cpp 1970-01-01 00:00:00 +0000
3095+++ mixxx/src/midi/mididevice.cpp 2009-11-10 00:33:17 +0000
3096@@ -0,0 +1,201 @@
3097+/***************************************************************************
3098+ mididevice.cpp
3099+ MIDI Device Class
3100+ -------------------
3101+ begin : Thu Dec 18 2008
3102+ copyright : (C) 2008 Albert Santoni
3103+ email : alberts@mixxx.org
3104+
3105+***************************************************************************/
3106+
3107+/***************************************************************************
3108+* *
3109+* This program is free software; you can redistribute it and/or modify *
3110+* it under the terms of the GNU General Public License as published by *
3111+* the Free Software Foundation; either version 2 of the License, or *
3112+* (at your option) any later version. *
3113+* *
3114+***************************************************************************/
3115+
3116+#include <qapplication.h> // For command line arguments
3117+#include "mididevice.h"
3118+#include "midimapping.h"
3119+#include "midimessage.h"
3120+#include "mixxxcontrol.h"
3121+#include "controlobject.h"
3122+
3123+#ifdef __MIDISCRIPT__
3124+#include "midiscriptengine.h"
3125+#endif
3126+
3127+static QString toHex(QString numberStr) {
3128+ return "0x" + QString("0" + QString::number(numberStr.toUShort(), 16).toUpper()).right(2);
3129+}
3130+
3131+MidiDevice::MidiDevice(MidiMapping* mapping) : QObject()
3132+{
3133+ m_bIsOutputDevice = false;
3134+ m_bIsInputDevice = false;
3135+ m_pMidiMapping = mapping;
3136+ m_pCorrespondingOutputDevice = NULL;
3137+ m_bIsOpen = false;
3138+ m_bMidiLearn = false;
3139+
3140+ if (m_pMidiMapping == NULL) {
3141+ m_pMidiMapping = new MidiMapping(this);
3142+ m_pMidiMapping->setName(m_strDeviceName);
3143+ }
3144+
3145+ // Get --midiDebug command line option
3146+ QStringList commandLineArgs = QApplication::arguments();
3147+ m_midiDebug = commandLineArgs.indexOf("--midiDebug");
3148+
3149+ connect(m_pMidiMapping, SIGNAL(midiLearningStarted()), this, SLOT(enableMidiLearn()));
3150+ connect(m_pMidiMapping, SIGNAL(midiLearningFinished()), this, SLOT(disableMidiLearn()));
3151+
3152+}
3153+
3154+MidiDevice::~MidiDevice()
3155+{
3156+ qDebug() << "MidiDevice: Deleting MidiMapping...";
3157+ delete m_pMidiMapping;
3158+
3159+}
3160+
3161+void MidiDevice::startup()
3162+{
3163+#ifdef __MIDISCRIPT__
3164+ m_pMidiMapping->startupScriptEngine();
3165+#endif
3166+}
3167+
3168+void MidiDevice::shutdown()
3169+{
3170+#ifdef __MIDISCRIPT__
3171+ m_pMidiMapping->shutdownScriptEngine();
3172+#endif
3173+}
3174+
3175+void MidiDevice::setMidiMapping(MidiMapping* mapping)
3176+{
3177+ m_pMidiMapping = mapping;
3178+
3179+ if (m_pCorrespondingOutputDevice)
3180+ {
3181+ m_pCorrespondingOutputDevice->setMidiMapping(m_pMidiMapping);
3182+ }
3183+}
3184+
3185+void MidiDevice::sendShortMsg(unsigned char status, unsigned char byte1, unsigned char byte2) {
3186+ unsigned int word = (((unsigned int)byte2) << 16) |
3187+ (((unsigned int)byte1) << 8) | status;
3188+ sendShortMsg(word);
3189+}
3190+
3191+void MidiDevice::sendShortMsg(unsigned int word) {
3192+ qDebug() << "MIDI short message sending not yet implemented for this API or platform";
3193+}
3194+
3195+void MidiDevice::sendSysexMsg(QList<int> data, unsigned int length) {
3196+ unsigned char * sysexMsg;
3197+ sysexMsg = new unsigned char [length];
3198+
3199+ for (unsigned int i=0; i<length; i++) {
3200+ sysexMsg[i] = data.at(i);
3201+// qDebug() << "sysexMsg" << i << "=" << sysexMsg[i] << ", data=" << data.at(i);
3202+ }
3203+
3204+ sendSysexMsg(sysexMsg,length);
3205+ delete[] sysexMsg;
3206+}
3207+
3208+void MidiDevice::sendSysexMsg(unsigned char data[], unsigned int length) {
3209+ qDebug() << "MIDI system exclusive message sending not yet implemented for this API or platform";
3210+}
3211+
3212+bool MidiDevice::getMidiLearnStatus() {
3213+ return m_bMidiLearn;
3214+}
3215+
3216+void MidiDevice::enableMidiLearn() {
3217+ m_bMidiLearn = true;
3218+ connect(this, SIGNAL(midiEvent(MidiMessage)), m_pMidiMapping, SLOT(finishMidiLearn(MidiMessage)));
3219+
3220+}
3221+
3222+void MidiDevice::disableMidiLearn() {
3223+ m_bMidiLearn = false;
3224+ disconnect(this, SIGNAL(midiEvent(MidiMessage)), m_pMidiMapping, SLOT(finishMidiLearn(MidiMessage)));
3225+}
3226+
3227+void MidiDevice::receive(MidiStatusByte status, char channel, char control, char value)
3228+{
3229+ if (midiDebugging()) qDebug() << QString("MIDI ch %1: status: %2, ctrl: %3, val: %4")
3230+ .arg(QString::number(channel+1, 16).toUpper())
3231+ .arg(QString::number(status & 255, 16).toUpper())
3232+ .arg(QString::number(control, 16).toUpper())
3233+ .arg(QString::number(value, 16).toUpper());
3234+
3235+ MidiMessage inputCommand(status, control, channel);
3236+
3237+ if (m_bMidiLearn) {
3238+ emit(midiEvent(inputCommand));
3239+ return; // Don't process midi messages further when MIDI learning
3240+ }
3241+
3242+ // Only check for a mapping if the status byte is one we know how to handle
3243+ if (status == MIDI_STATUS_NOTE_ON
3244+ || status == MIDI_STATUS_NOTE_OFF
3245+ || status == MIDI_STATUS_PITCH_BEND
3246+ || status == MIDI_STATUS_CC) {
3247+ // If there was no control bound to that MIDI command, return;
3248+ if (!m_pMidiMapping->isMidiMessageMapped(inputCommand)) {
3249+ return;
3250+ }
3251+ }
3252+
3253+ MixxxControl mixxxControl = m_pMidiMapping->getInputMixxxControl(inputCommand);
3254+ //qDebug() << "MidiDevice: " << mixxxControl.getControlObjectGroup() << mixxxControl.getControlObjectValue();
3255+
3256+ ConfigKey configKey(mixxxControl.getControlObjectGroup(), mixxxControl.getControlObjectValue());
3257+
3258+#ifdef __MIDISCRIPT__
3259+ // Custom MixxxScript (QtScript) handler
3260+ //FIXME: SEAN - The script engine will live inside the MidiMapping! Update this code accordingly.
3261+
3262+ if (mixxxControl.getMidiOption() == MIDI_OPT_SCRIPT) {
3263+ // qDebug() << "MidiDevice: Calling script function" << configKey.item << "with" << (int)channel << (int)control << (int)value << (int)status;
3264+
3265+ if (!m_pMidiMapping->getMidiScriptEngine()->execute(configKey.item, channel, control, value, status, mixxxControl.getControlObjectGroup())) {
3266+ qDebug() << "MidiDevice: Invalid script function" << configKey.item;
3267+ }
3268+ return;
3269+ }
3270+#endif
3271+
3272+ ControlObject * p = ControlObject::getControl(configKey);
3273+
3274+ if (p) //Only pass values on to valid ControlObjects.
3275+ {
3276+ double newValue = m_pMidiMapping->ComputeValue(mixxxControl.getMidiOption(), p->GetMidiValue(), value);
3277+
3278+ // ControlPushButton ControlObjects only accept NOTE_ON, so if the midi mapping is <button> we override the Midi 'status' appropriately.
3279+ switch (mixxxControl.getMidiOption()) {
3280+ case MIDI_OPT_BUTTON:
3281+ case MIDI_OPT_SWITCH: status = MIDI_STATUS_NOTE_ON; break; // Buttons and Switches are treated the same, except that their values are computed differently.
3282+ default: break;
3283+ }
3284+
3285+ ControlObject::sync();
3286+
3287+ //Super dangerous cast here... Should be fine once MidiCategory is replaced with MidiStatusByte permanently.
3288+ p->queueFromMidi((MidiCategory)status, newValue);
3289+ }
3290+
3291+ return;
3292+}
3293+
3294+bool MidiDevice::midiDebugging() {
3295+ if (m_midiDebug != -1) return true;
3296+ else return false;
3297+}
3298
3299=== added file 'mixxx/src/midi/mididevice.h'
3300--- mixxx/src/midi/mididevice.h 1970-01-01 00:00:00 +0000
3301+++ mixxx/src/midi/mididevice.h 2009-11-10 00:33:17 +0000
3302@@ -0,0 +1,82 @@
3303+/***************************************************************************
3304+ mididevice.h
3305+ MIDI Device Class
3306+ -------------------
3307+ begin : Thu Dec 18 2008
3308+ copyright : (C) 2008 Albert Santoni
3309+ email : alberts@mixxx.org
3310+
3311+***************************************************************************/
3312+
3313+/***************************************************************************
3314+* *
3315+* This program is free software; you can redistribute it and/or modify *
3316+* it under the terms of the GNU General Public License as published by *
3317+* the Free Software Foundation; either version 2 of the License, or *
3318+* (at your option) any later version. *
3319+* *
3320+***************************************************************************/
3321+
3322+#ifndef MIDIDEVICE_H
3323+#define MIDIDEVICE_H
3324+
3325+#include <QtCore>
3326+#include "midimessage.h"
3327+
3328+//Forward declarations
3329+class MidiMapping;
3330+#ifdef __MIDISCRIPT__
3331+class MidiScriptEngine;
3332+#endif
3333+
3334+class MidiDevice : public QObject
3335+{
3336+Q_OBJECT
3337+ public:
3338+ MidiDevice(MidiMapping* mapping);
3339+ virtual ~MidiDevice();
3340+ virtual int open() = 0;
3341+ virtual int close() = 0;
3342+ void startup();
3343+ void shutdown();
3344+ bool isOpen() { return m_bIsOpen; };
3345+ bool isOutputDevice() { return m_bIsOutputDevice; };
3346+ bool isInputDevice() { return m_bIsInputDevice; };
3347+ QString getName() { return m_strDeviceName; };
3348+ void setMidiMapping(MidiMapping* mapping);
3349+ MidiMapping* getMidiMapping() { return m_pMidiMapping; };
3350+ Q_INVOKABLE void sendShortMsg(unsigned char status, unsigned char byte1, unsigned char byte2);
3351+ virtual void sendShortMsg(unsigned int word);
3352+ virtual void sendSysexMsg(unsigned char data[], unsigned int length);
3353+ Q_INVOKABLE void sendSysexMsg(QList<int> data, unsigned int length);
3354+ bool getMidiLearnStatus();
3355+ void receive(MidiStatusByte status, char channel, char control, char value);
3356+ bool midiDebugging();
3357+
3358+ public slots:
3359+ void disableMidiLearn();
3360+ void enableMidiLearn();
3361+
3362+ signals:
3363+ void midiEvent(MidiMessage message);
3364+ protected:
3365+ /** Verbose device name, in format "[index]. [device name]". Suitable for display in GUI. */
3366+ QString m_strDeviceName;
3367+ /** Flag indicating if this device supports MIDI output */
3368+ bool m_bIsOutputDevice;
3369+ /** Flag indicating if this device supports MIDI input */
3370+ bool m_bIsInputDevice;
3371+ /** MIDI Mapping for this MIDI device, maps MIDI messages onto Mixxx controls */
3372+ MidiMapping* m_pMidiMapping;
3373+ /** Indicates whether or not the MIDI device has been opened for input/output. */
3374+ bool m_bIsOpen;
3375+ /** Indicates whether MIDI learning is currently enabled or not */
3376+ bool m_bMidiLearn;
3377+ /** Pointer to the output device that corresponds to this physical input device. MIDI is a half-duplex
3378+ protocol that treats input and output ports on a single device as complete separate entities. This
3379+ helps us group those back together for sanity/usability. */
3380+ MidiDevice* m_pCorrespondingOutputDevice;
3381+ int m_midiDebug;
3382+};
3383+
3384+#endif
3385
3386=== added file 'mixxx/src/midi/mididevicedummy.h'
3387--- mixxx/src/midi/mididevicedummy.h 1970-01-01 00:00:00 +0000
3388+++ mixxx/src/midi/mididevicedummy.h 2009-11-10 00:33:17 +0000
3389@@ -0,0 +1,41 @@
3390+/**
3391+ * @file mididevicedummy.h
3392+ * @author Albert Santoni alberts@mixxx.org
3393+ * @date Sun Aug 9 2009
3394+ * @brief Dummy MIDI backend
3395+ *
3396+ */
3397+
3398+/***************************************************************************
3399+ * *
3400+ * This program is free software; you can redistribute it and/or modify *
3401+ * it under the terms of the GNU General Public License as published by *
3402+ * the Free Software Foundation; either version 2 of the License, or *
3403+ * (at your option) any later version. *
3404+ * *
3405+ ***************************************************************************/
3406+
3407+#ifndef MIDIDEVICEDUMMY_H
3408+#define MIDIDEVICEDUMMY_H
3409+
3410+#include <QtCore>
3411+#include "mididevice.h"
3412+
3413+/**
3414+ *@author Albert Santoni
3415+ */
3416+
3417+/** A dummy implementation of MidiDevice */
3418+class MidiDeviceDummy : public MidiDevice {
3419+public:
3420+ MidiDeviceDummy(MidiMapping* mapping=NULL) : MidiDevice(mapping) { setObjectName("Dummy MIDI Device");};
3421+ ~MidiDeviceDummy() {};
3422+ int open() { return 0; };
3423+ int close() { return 0; };
3424+ void sendShortMsg(unsigned int word) {};
3425+ void sendSysexMsg(unsigned char data[], unsigned int length) {};
3426+protected:
3427+
3428+};
3429+
3430+#endif
3431
3432=== added file 'mixxx/src/midi/mididevicemanager.cpp'
3433--- mixxx/src/midi/mididevicemanager.cpp 1970-01-01 00:00:00 +0000
3434+++ mixxx/src/midi/mididevicemanager.cpp 2009-11-10 00:33:17 +0000
3435@@ -0,0 +1,299 @@
3436+/**
3437+ * @file mididevicemanager.cpp
3438+ * @author Albert Santoni alberts@mixxx.org & Sean Pappalardo pegasus@c64.org
3439+ * @date Thu Dec 18 2008
3440+ * @brief Manages creation/enumeration/deletion of MidiDevices.
3441+ */
3442+
3443+/***************************************************************************
3444+* *
3445+* This program is free software; you can redistribute it and/or modify *
3446+* it under the terms of the GNU General Public License as published by *
3447+* the Free Software Foundation; either version 2 of the License, or *
3448+* (at your option) any later version. *
3449+* *
3450+***************************************************************************/
3451+
3452+#include <QtCore>
3453+#include "mididevice.h"
3454+//#include "midilearnlistener.h"
3455+//#include "midilearningprocessor.h"
3456+//#include "midicontrolprocessor.h"
3457+#include "midideviceportmidi.h"
3458+#include "dlgprefmidibindings.h"
3459+#include "mididevicemanager.h"
3460+#include "../mixxxcontrol.h"
3461+#include "midimapping.h"
3462+
3463+#define DEVICE_CONFIG_PATH BINDINGS_PATH.append("MixxxMIDIDevices")
3464+
3465+MidiDeviceManager::MidiDeviceManager(ConfigObject<ConfigValue> * pConfig) : QObject()
3466+{
3467+ m_pConfig = pConfig;
3468+ m_pPrimaryMidiDevice = NULL;
3469+ m_pDeviceSettings = new ConfigObject<ConfigValue>(DEVICE_CONFIG_PATH);
3470+}
3471+
3472+MidiDeviceManager::~MidiDeviceManager()
3473+{
3474+ closeDevices();
3475+}
3476+
3477+void MidiDeviceManager::saveMappings(bool onlyActive) {
3478+ // Write out MIDI mappings for currently connected devices
3479+ QList<MidiDevice*> deviceList = getDeviceList(false, true);
3480+ QListIterator<MidiDevice*> it(deviceList);
3481+
3482+ QList<QString> filenames;
3483+
3484+ while (it.hasNext())
3485+ {
3486+ MidiDevice *cur= it.next();
3487+ if (onlyActive && !cur->isOpen()) continue;
3488+ MidiMapping *mapping = cur->getMidiMapping();
3489+ QString name = cur->getName();
3490+
3491+ QString ofilename = name.right(name.size()-name.indexOf(" ")-1).replace(" ", "_");
3492+
3493+ QString filename = ofilename;
3494+
3495+ int i=1;
3496+ while (filenames.contains(filename)) {
3497+ i++;
3498+ filename = QString("%1--%2").arg(ofilename).arg(i);
3499+ }
3500+
3501+ filenames.append(filename);
3502+ mapping->savePreset(BINDINGS_PATH.append(filename + MIDI_MAPPING_EXTENSION));
3503+ }
3504+}
3505+
3506+QList<MidiDevice*> MidiDeviceManager::getDeviceList(bool bOutputDevices, bool bInputDevices)
3507+{
3508+ qDebug() << "MidiDeviceManager::getDeviceList";
3509+ bool bMatchedCriteria = false; //Whether or not the current device matched the filtering criteria
3510+
3511+ if (m_devices.empty())
3512+ this->queryDevices();
3513+
3514+ //Create a list of MIDI devices filtered to match the given input/output options.
3515+ QList<MidiDevice*> filteredDeviceList;
3516+ QListIterator<MidiDevice*> dev_it(m_devices);
3517+ while (dev_it.hasNext())
3518+ {
3519+ bMatchedCriteria = false; //Reset this for the next device.
3520+ MidiDevice *device = dev_it.next();
3521+
3522+ if ((bOutputDevices == device->isOutputDevice()) ||
3523+ (bInputDevices == device->isInputDevice())) {
3524+ bMatchedCriteria = true;
3525+ }
3526+
3527+ if (bMatchedCriteria)
3528+ filteredDeviceList.push_back(device);
3529+ }
3530+ return filteredDeviceList;
3531+}
3532+
3533+void MidiDeviceManager::closeDevices()
3534+{
3535+ QListIterator<MidiDevice*> dev_it(m_devices);
3536+ while (dev_it.hasNext())
3537+ {
3538+ qDebug() << "Closing MIDI device" << dev_it.peekNext()->getName();
3539+ dev_it.next()->close();
3540+ }
3541+}
3542+
3543+/** Enumerate the MIDI devices
3544+ * This method needs a bit of intelligence because PortMidi (and the underlying MIDI APIs) like to split
3545+ * output and input into separate devices. Eg. PortMidi would tell us the Hercules is two half-duplex devices.
3546+ * To help simplify a lot of code, we're going to aggregate these two streams into a single full-duplex device.
3547+ */
3548+void MidiDeviceManager::queryDevices()
3549+{
3550+ qDebug() << "Scanning MIDI devices:";
3551+ int iNumDevices = Pm_CountDevices();
3552+
3553+ QListIterator<MidiDevice*> dev_it(m_devices);
3554+ while (dev_it.hasNext()) {
3555+ delete dev_it.next();
3556+ }
3557+
3558+ m_devices.clear();
3559+
3560+ const PmDeviceInfo *deviceInfo, *inputDeviceInfo, *outputDeviceInfo;
3561+ int inputDevIndex, outputDevIndex;
3562+ QMap<int,QString> unassignedOutputDevices;
3563+
3564+ // Build a complete list of output devices for later pairing
3565+ for (int i = 0; i < iNumDevices; i++)
3566+ {
3567+ deviceInfo = Pm_GetDeviceInfo(i);
3568+ if (deviceInfo->output) {
3569+ qDebug() << " Found output device" << "#" << i << deviceInfo->name;
3570+ QString deviceName = deviceInfo->name;
3571+ // Ignore "To" text in the device names
3572+ if (deviceName.indexOf("to",0,Qt::CaseInsensitive)!=-1) deviceName = deviceName.right(deviceName.length()-2);
3573+ unassignedOutputDevices[i] = deviceName;
3574+ }
3575+ }
3576+
3577+ // Search for input devices and pair them with output devices if applicable
3578+ for (int i = 0; i < iNumDevices; i++)
3579+ {
3580+ deviceInfo = Pm_GetDeviceInfo(i);
3581+
3582+ //If we found an input device
3583+ if (deviceInfo->input)
3584+ {
3585+ qDebug() << " Found input device" << "#" << i << deviceInfo->name;
3586+ inputDeviceInfo = deviceInfo;
3587+ inputDevIndex = i;
3588+
3589+ //Reset our output device variables before we look for one incase we find none.
3590+ outputDeviceInfo = NULL;
3591+ outputDevIndex = -1;
3592+
3593+ //Search for a corresponding output device
3594+ QMapIterator<int, QString> j(unassignedOutputDevices);
3595+ while (j.hasNext()) {
3596+ j.next();
3597+
3598+ // Ignore "From" text in the device names
3599+ QString deviceName = inputDeviceInfo->name;
3600+ if (deviceName.indexOf("from",0,Qt::CaseInsensitive)!=-1) deviceName = deviceName.right(deviceName.length()-4);
3601+
3602+ QByteArray outputName = QString(j.value()).toUtf8();
3603+ if (strcmp(outputName, deviceName) == 0) {
3604+ outputDevIndex = j.key();
3605+ outputDeviceInfo = Pm_GetDeviceInfo(outputDevIndex);
3606+
3607+ unassignedOutputDevices.remove(outputDevIndex);
3608+
3609+ qDebug() << " Linking to output device #" << outputDevIndex << outputName;
3610+ break;
3611+ }
3612+ }
3613+
3614+ //So at this point in the code, we either have an input-only MIDI device (outputDeviceInfo == NULL)
3615+ //or we've found a matching output MIDI device (outputDeviceInfo != NULL).
3616+
3617+ //.... so create our (aggregate) MIDI device!
3618+ MidiDevicePortMidi *currentDevice = new MidiDevicePortMidi(/*new MidiControlProcessor(NULL)*/ NULL,
3619+ inputDeviceInfo,
3620+ outputDeviceInfo,
3621+ inputDevIndex,
3622+ outputDevIndex);
3623+ m_devices.push_back((MidiDevice*)currentDevice);
3624+
3625+ }
3626+
3627+// if (deviceInfo->input || deviceInfo->output)
3628+// {
3629+// MidiDevicePortMidi *currentDevice = new MidiDevicePortMidi(new MidiControlProcessor(NULL), deviceInfo, i);
3630+// m_devices.push_back((MidiDevice*)currentDevice);
3631+// }
3632+ }
3633+}
3634+
3635+/** Open whatever MIDI devices are selected in the preferences. */
3636+int MidiDeviceManager::setupDevices()
3637+{
3638+ QList<MidiDevice*> deviceList = getDeviceList(false, true);
3639+ QListIterator<MidiDevice*> it(deviceList);
3640+
3641+ qDebug() << "MidiDeviceManager: Setting up devices";
3642+
3643+ QList<QString> filenames;
3644+
3645+ while (it.hasNext())
3646+ {
3647+ MidiDevice *cur= it.next();
3648+ MidiMapping *mapping = cur->getMidiMapping();
3649+ QString name = cur->getName();
3650+ mapping->setName(name);
3651+
3652+ cur->close();
3653+
3654+ QString ofilename = name.right(name.size()-name.indexOf(" ")-1).replace(" ", "_");
3655+
3656+ QString filename = ofilename;
3657+
3658+ int i=1;
3659+ while (filenames.contains(filename)) {
3660+ i++;
3661+ filename = QString("%1--%2").arg(ofilename).arg(i);
3662+ }
3663+
3664+ filenames.append(filename);
3665+ mapping->loadPreset(BINDINGS_PATH.append(filename + MIDI_MAPPING_EXTENSION),true);
3666+
3667+ if ( m_pConfig->getValueString(ConfigKey("[Midi]", name.replace(" ", "_"))) != "1" )
3668+ continue;
3669+
3670+ qDebug() << "Opening Device:" << name;
3671+
3672+ cur->open();
3673+ mapping->applyPreset();
3674+
3675+ }
3676+
3677+ return 0;
3678+}
3679+
3680+
3681+/** This should be in MidiProcessor because it's bindings related */
3682+QStringList MidiDeviceManager::getConfigList(QString path)
3683+{
3684+ // Make sure list is empty
3685+ QStringList configs;
3686+ configs.clear();
3687+
3688+ // Get list of available midi configurations
3689+ QDir dir(path);
3690+ dir.setFilter(QDir::Files);
3691+ dir.setNameFilters(QStringList() << "*.midi.xml" << "*.MIDI.XML");
3692+
3693+ //const QFileInfoList *list = dir.entryInfoList();
3694+ //if (dir.entryInfoList().empty())
3695+ {
3696+ QListIterator<QFileInfo> it(dir.entryInfoList());
3697+ QFileInfo fi; // pointer for traversing
3698+ while (it.hasNext())
3699+ {
3700+ fi = it.next();
3701+ configs.append(fi.fileName());
3702+ }
3703+ }
3704+
3705+ return configs;
3706+}
3707+
3708+
3709+void MidiDeviceManager::associateInputAndOutputDevices(MidiDevice* inputDevice, QString outputDeviceName)
3710+{
3711+ //TODO: This function needs to be updated to work with our "aggregate" input/ouput MidiDevice class
3712+ // or just simply removed all together. I just sent out a mixxx-devel email with more history
3713+ // on this, check the archive if you need more info. -- Albert Nov 9/09 (1.8 CRUNCH TIME!)
3714+ //
3715+
3716+/*
3717+ //Find the output MidiDevice object that corresponds to outputDeviceName.
3718+ QListIterator<MidiDevice*> dev_it(m_devices);
3719+ MidiDevice* outputDevice = NULL;
3720+ while (dev_it.hasNext()) {
3721+ outputDevice = dev_it.next();
3722+ if (outputDevice->getName() == outputDeviceName) {
3723+ qDebug() << "associating input dev" << inputDevice->getName() << "with" << outputDeviceName;
3724+ break;
3725+ }
3726+ }
3727+
3728+ if (outputDevice == NULL) //No output device matched outputDeviceName...
3729+ return;
3730+
3731+ //Tell the input device that it's corresponding output device is... outputDevice.
3732+ inputDevice->setOutputDevice(outputDevice);
3733+ */
3734+}
3735
3736=== added file 'mixxx/src/midi/mididevicemanager.h'
3737--- mixxx/src/midi/mididevicemanager.h 1970-01-01 00:00:00 +0000
3738+++ mixxx/src/midi/mididevicemanager.h 2009-11-10 00:33:17 +0000
3739@@ -0,0 +1,53 @@
3740+/**
3741+ * @file mididevicemanager.h
3742+ * @author Albert Santoni alberts@mixxx.org
3743+ * @date Thu Dec 18 2008
3744+ * @brief Manages creation/enumeration/deletion of MidiDevices.
3745+ */
3746+
3747+/***************************************************************************
3748+* *
3749+* This program is free software; you can redistribute it and/or modify *
3750+* it under the terms of the GNU General Public License as published by *
3751+* the Free Software Foundation; either version 2 of the License, or *
3752+* (at your option) any later version. *
3753+* *
3754+***************************************************************************/
3755+
3756+#ifndef MIDIDEVICEMANAGER_H
3757+#define MIDIDEVICEMANAGER_H
3758+
3759+#include "configobject.h"
3760+class MidiDevice;
3761+class MidiLearnListener;
3762+class MidiLearnProcessor;
3763+class DlgPrefMidiBindings;
3764+
3765+/** Manages creation/enumeration/deletion of MidiDevices. */
3766+class MidiDeviceManager : public QObject
3767+{
3768+ Q_OBJECT
3769+ public:
3770+ MidiDeviceManager(ConfigObject<ConfigValue> * pConfig);
3771+ ~MidiDeviceManager();
3772+ QList<MidiDevice*> getDeviceList(bool bOutputDevices=true, bool bInputDevice=true);
3773+ QStringList getConfigList(QString path);
3774+ void saveMappings(bool onlyActive=false);
3775+ void closeDevices();
3776+ void queryDevices();
3777+ int setupDevices();
3778+ ConfigObject<ConfigValue>* getDeviceSettings() { return m_pDeviceSettings; };
3779+ void associateInputAndOutputDevices(MidiDevice* inputDevice, QString outputDeviceName);
3780+ /* MidiDevice* getPrimaryMidiDevice() { return m_pPrimaryMidiDevice; }; //HACK while our code still sucks
3781+ void enableMidiLearn(DlgPrefMidiBindings* listener);
3782+ void disableMidiLearn(); */ //Moving MIDI learning into MIDI device, a la 1.7.0
3783+ signals:
3784+ void devicesChanged();
3785+ private:
3786+ QList<MidiDevice*> m_devices;
3787+ ConfigObject<ConfigValue> *m_pDeviceSettings;
3788+ ConfigObject<ConfigValue> *m_pConfig;
3789+ MidiDevice* m_pPrimaryMidiDevice;
3790+ };
3791+
3792+#endif
3793
3794=== added file 'mixxx/src/midi/midideviceportmidi.cpp'
3795--- mixxx/src/midi/midideviceportmidi.cpp 1970-01-01 00:00:00 +0000
3796+++ mixxx/src/midi/midideviceportmidi.cpp 2009-11-10 00:33:17 +0000
3797@@ -0,0 +1,245 @@
3798+/**
3799+ * @file midideviceportmidi.cpp
3800+ * @author Albert Santoni alberts@mixxx.org
3801+ * @date Thu Dec 18 2008
3802+ * @brief PortMidi-based MIDI backend
3803+ *
3804+ * MidiDevicePortMidi is a class representing a MIDI device, either
3805+ * physical or software. It uses the PortMidi API to send and receive
3806+ * MIDI events to/from the device. It's important to note that PortMidi
3807+ * treats input and output on a single physical device as two separate
3808+ * half-duplex devices. In this class, we wrap those together into a
3809+ * single device, which is why the MidiDevicePortMidi constructor takes
3810+ * both arguments pertaining to both input and output "devices".
3811+ *
3812+ *
3813+ */
3814+
3815+/***************************************************************************
3816+* *
3817+* This program is free software; you can redistribute it and/or modify *
3818+* it under the terms of the GNU General Public License as published by *
3819+* the Free Software Foundation; either version 2 of the License, or *
3820+* (at your option) any later version. *
3821+* *
3822+***************************************************************************/
3823+
3824+#include <QtCore>
3825+#include "configobject.h"
3826+#include "midimapping.h"
3827+#include "midideviceportmidi.h"
3828+
3829+QMutex MidiDevicePortMidi::m_sPMLock; // PortMidi is not thread-safe
3830+
3831+MidiDevicePortMidi::MidiDevicePortMidi(MidiMapping* mapping,
3832+ const PmDeviceInfo* inputDeviceInfo,
3833+ const PmDeviceInfo* outputDeviceInfo,
3834+ int inputDeviceIndex,
3835+ int outputDeviceIndex)
3836+ : MidiDevice(mapping), QThread()
3837+{
3838+ m_pInputStream = NULL;
3839+ m_pOutputStream = NULL;
3840+ m_bStopRequested = false;
3841+ m_pInputDeviceInfo = inputDeviceInfo;
3842+ m_pOutputDeviceInfo = outputDeviceInfo;
3843+ m_iInputDeviceIndex = inputDeviceIndex;
3844+ m_iOutputDeviceIndex = outputDeviceIndex;
3845+
3846+ //Note: We prepend the input stream's index to the device's name to prevent duplicate devices from causing mayhem.
3847+ m_strDeviceName = QString("%1. %2").arg(QString::number(m_iInputDeviceIndex)).arg(inputDeviceInfo->name);
3848+
3849+ if (inputDeviceInfo) {
3850+ m_bIsInputDevice = m_pInputDeviceInfo->input;
3851+ }
3852+ if (outputDeviceInfo) {
3853+ m_bIsOutputDevice = m_pOutputDeviceInfo->output;
3854+ }
3855+}
3856+
3857+MidiDevicePortMidi::~MidiDevicePortMidi()
3858+{
3859+ close();
3860+}
3861+
3862+int MidiDevicePortMidi::open()
3863+{
3864+ if (m_bIsOpen) {
3865+ qDebug() << "PortMIDI device" << m_strDeviceName << "already open";
3866+ return -1;
3867+ }
3868+
3869+ startup();
3870+
3871+ m_bStopRequested = false;
3872+
3873+ if (m_strDeviceName == MIXXX_PORTMIDI_NO_DEVICE_STRING)
3874+ return -1;
3875+
3876+ PmError err = Pm_Initialize();
3877+ if( err != pmNoError )
3878+ {
3879+ qDebug() << "PortMidi error:" << Pm_GetErrorText(err);
3880+ return -1;
3881+ }
3882+
3883+ if (m_pInputDeviceInfo)
3884+ {
3885+ if (m_bIsInputDevice)
3886+ {
3887+ if (midiDebugging()) qDebug() << "MidiDevicePortMidi: Opening" << m_pInputDeviceInfo->name << "index" << m_iInputDeviceIndex << "for input";
3888+
3889+ err = Pm_OpenInput( &m_pInputStream,
3890+ m_iInputDeviceIndex,
3891+ NULL, //No drive hacks
3892+ MIXXX_PORTMIDI_BUFFER_LEN,
3893+ NULL,
3894+ NULL);
3895+
3896+ if( err != pmNoError )
3897+ {
3898+ qDebug() << "PortMidi error:" << Pm_GetErrorText(err);
3899+ return -2;
3900+ }
3901+ }
3902+ }
3903+ if (m_pOutputDeviceInfo)
3904+ {
3905+ if (m_bIsOutputDevice)
3906+ {
3907+ if (midiDebugging()) qDebug() << "MidiDevicePortMidi: Opening" << m_pOutputDeviceInfo->name << "index" << m_iOutputDeviceIndex << "for output";
3908+
3909+ err = Pm_OpenOutput( &m_pOutputStream,
3910+ m_iOutputDeviceIndex,
3911+ NULL, // No driver hacks
3912+ 0, // No buffering
3913+ NULL, // Use PortTime for timing
3914+ NULL, // No time info
3915+ 0); // No latency compensation.
3916+
3917+ if( err != pmNoError )
3918+ {
3919+ qDebug() << "PortMidi error:" << Pm_GetErrorText(err);
3920+ return -2;
3921+ }
3922+ }
3923+ }
3924+
3925+ m_bIsOpen = true;
3926+ start();
3927+
3928+ return 0;
3929+
3930+}
3931+
3932+int MidiDevicePortMidi::close()
3933+{
3934+ if (!m_bIsOpen) {
3935+ qDebug() << "PortMIDI device" << m_strDeviceName << "already closed";
3936+ return -1;
3937+ }
3938+
3939+ shutdown();
3940+
3941+ m_bStopRequested = true;
3942+ m_mutex.lock();
3943+
3944+ if (m_pInputStream)
3945+ {
3946+ m_sPMLock.lock();
3947+ PmError err = Pm_Close(m_pInputStream);
3948+ if( err != pmNoError )
3949+ {
3950+ qDebug() << "PortMidi error:" << Pm_GetErrorText(err);
3951+ m_sPMLock.unlock();
3952+ return -1;
3953+ }
3954+ m_sPMLock.unlock();
3955+ }
3956+
3957+ if (m_pOutputStream)
3958+ {
3959+ m_sPMLock.lock();
3960+ PmError err = Pm_Close(m_pOutputStream);
3961+ if( err != pmNoError )
3962+ {
3963+ qDebug() << "PortMidi error:" << Pm_GetErrorText(err);
3964+ m_sPMLock.unlock();
3965+ return -1;
3966+ }
3967+ m_sPMLock.unlock();
3968+ }
3969+
3970+ m_bIsOpen = false;
3971+
3972+ m_mutex.unlock();
3973+
3974+ return 0;
3975+}
3976+
3977+void MidiDevicePortMidi::run()
3978+{
3979+ QThread::currentThread()->setObjectName(QString("PM %1").arg(m_strDeviceName));
3980+ int numEvents = 0;
3981+ bool stopRunning = false;
3982+
3983+
3984+ do
3985+ {
3986+ m_mutex.lock();
3987+ if (m_pInputStream)
3988+ {
3989+ m_sPMLock.lock();
3990+ numEvents = Pm_Read(m_pInputStream, m_midiBuffer, MIXXX_PORTMIDI_BUFFER_LEN);
3991+ m_sPMLock.unlock();
3992+
3993+ for (int i = 0; i < numEvents; i++)
3994+ {
3995+ //if (Pm_MessageStatus(m_midiBuffer[i].message) == 0x90) //Note on, channel 1
3996+ {
3997+ m_sPMLock.lock();
3998+ unsigned char status = Pm_MessageStatus(m_midiBuffer[i].message);
3999+ unsigned char opcode = status & 0xF0;
4000+ unsigned char channel = status & 0x0F;
4001+ unsigned char note = Pm_MessageData1(m_midiBuffer[i].message);
4002+ unsigned char velocity = Pm_MessageData2(m_midiBuffer[i].message);
4003+ m_sPMLock.unlock();
4004+
4005+ MidiDevice::receive((MidiStatusByte)status, channel, note, velocity);
4006+
4007+ }
4008+ }
4009+ }
4010+
4011+ usleep(5000); //Sleep this thread for 5 milliseconds between checking for new MIDI events.
4012+
4013+ stopRunning = m_bStopRequested; //Cache locally for thread-safety.
4014+ m_mutex.unlock(); //Have to unlock inside the loop to give the other thread a chance to lock.
4015+
4016+ } while (!stopRunning);
4017+
4018+
4019+}
4020+
4021+void MidiDevicePortMidi::sendShortMsg(unsigned int word)
4022+{
4023+ if (m_pOutputStream)
4024+ {
4025+ m_sPMLock.lock();
4026+ PmError err = Pm_WriteShort(m_pOutputStream, 0, word);
4027+ if( err != pmNoError ) qDebug() << "PortMidi sendShortMsg error:" << Pm_GetErrorText(err);
4028+ m_sPMLock.unlock();
4029+ }
4030+}
4031+
4032+// The sysex data must already contain the start byte 0xf0 and the end byte 0xf7.
4033+void MidiDevicePortMidi::sendSysexMsg(unsigned char data[], unsigned int length)
4034+{
4035+ if (m_pOutputStream)
4036+ {
4037+ m_sPMLock.lock();
4038+ PmError err = Pm_WriteSysEx(m_pOutputStream, 0, data);
4039+ if( err != pmNoError ) qDebug() << "PortMidi sendSysexMsg error:" << Pm_GetErrorText(err);
4040+ m_sPMLock.unlock();
4041+ }
4042+}
4043
4044=== added file 'mixxx/src/midi/midideviceportmidi.h'
4045--- mixxx/src/midi/midideviceportmidi.h 1970-01-01 00:00:00 +0000
4046+++ mixxx/src/midi/midideviceportmidi.h 2009-11-10 00:33:17 +0000
4047@@ -0,0 +1,60 @@
4048+/**
4049+ * @file midideviceportmidi.h
4050+ * @author Albert Santoni alberts@mixxx.org
4051+ * @date Thu Dec 18 2008
4052+ * @brief PortMidi-based MIDI backend
4053+ *
4054+ */
4055+
4056+/***************************************************************************
4057+ * *
4058+ * This program is free software; you can redistribute it and/or modify *
4059+ * it under the terms of the GNU General Public License as published by *
4060+ * the Free Software Foundation; either version 2 of the License, or *
4061+ * (at your option) any later version. *
4062+ * *
4063+ ***************************************************************************/
4064+
4065+#ifndef MIDIDEVICEPORTMIDI_H
4066+#define MIDIDEVICEPORTMIDI_H
4067+
4068+#include <portmidi.h>
4069+#include <porttime.h>
4070+#include <QtCore>
4071+#include "mididevice.h"
4072+
4073+#define MIXXX_PORTMIDI_BUFFER_LEN 64 /**Number of MIDI messages to buffer*/
4074+#define MIXXX_PORTMIDI_NO_DEVICE_STRING "None" /**String to display for no MIDI devices present */
4075+/**
4076+ *@author Albert Santoni
4077+ */
4078+
4079+/** A PortMidi-based implementation of MidiDevice */
4080+class MidiDevicePortMidi : public MidiDevice, public QThread {
4081+public:
4082+ MidiDevicePortMidi(MidiMapping* mapping,
4083+ const PmDeviceInfo* inputDeviceInfo,
4084+ const PmDeviceInfo* outputDeviceInfo,
4085+ int inputDeviceIndex,
4086+ int outputDeviceIndex);
4087+ ~MidiDevicePortMidi();
4088+ int open();
4089+ int close();
4090+ void sendShortMsg(unsigned int word);
4091+ void sendSysexMsg(unsigned char data[], unsigned int length);
4092+protected:
4093+ void run();
4094+ const PmDeviceInfo* m_pInputDeviceInfo;
4095+ const PmDeviceInfo* m_pOutputDeviceInfo;
4096+ int m_iInputDeviceIndex;
4097+ int m_iOutputDeviceIndex;
4098+ PortMidiStream *m_pInputStream;
4099+ PortMidiStream *m_pOutputStream;
4100+ PmEvent m_midiBuffer[MIXXX_PORTMIDI_BUFFER_LEN];
4101+ static QList<QString> m_deviceList;
4102+ QMutex m_mutex;
4103+ static QMutex m_sPMLock; // PortMidi is not thread-safe, so we need to only allow one thread at a time
4104+ bool m_bStopRequested;
4105+};
4106+
4107+#endif
4108
4109=== renamed file 'mixxx/src/midiinputmapping.h' => 'mixxx/src/midi/midiinputmapping.h'
4110=== renamed file 'mixxx/src/midiinputmappingtablemodel.cpp' => 'mixxx/src/midi/midiinputmappingtablemodel.cpp'
4111=== renamed file 'mixxx/src/midiinputmappingtablemodel.h' => 'mixxx/src/midi/midiinputmappingtablemodel.h'
4112=== renamed file 'mixxx/src/midiledhandler.cpp' => 'mixxx/src/midi/midiledhandler.cpp'
4113--- mixxx/src/midiledhandler.cpp 2009-08-11 04:38:51 +0000
4114+++ mixxx/src/midi/midiledhandler.cpp 2009-11-10 00:33:17 +0000
4115@@ -6,9 +6,9 @@
4116
4117 Q3PtrList<MidiLedHandler> MidiLedHandler::allhandlers = Q3PtrList<MidiLedHandler>();
4118
4119-MidiLedHandler::MidiLedHandler(QString group, QString key, MidiObject & midi, double min,
4120- double max, unsigned char status, unsigned char midino, QString device, unsigned char on, unsigned char off)
4121- : m_min(min), m_max(max), m_midi(midi), m_status(status), m_midino(midino), m_device(device), m_on(on), m_off(off) {
4122+MidiLedHandler::MidiLedHandler(QString group, QString key, MidiDevice & midi, double min,
4123+ double max, unsigned char status, unsigned char midino, unsigned char on, unsigned char off)
4124+ : m_min(min), m_max(max), m_midi(midi), m_status(status), m_midino(midino), m_on(on), m_off(off) {
4125
4126 //OMGWTFBBQ: Massive hack to temporarily fix LP #254564 for the 1.6.0 release.
4127 // Something's funky with our <lights> blocks handling? -- Albert 08/05/2008
4128@@ -49,7 +49,7 @@
4129 m_reentracyBlock.unlock();
4130 }
4131
4132-void MidiLedHandler::createHandlers(QDomNode node, MidiObject & midi, QString device) {
4133+void MidiLedHandler::createHandlers(QDomNode node, MidiDevice & midi) {
4134 if (!node.isNull() && node.isElement()) {
4135 QDomNode light = node;
4136 while (!light.isNull()) {
4137@@ -78,8 +78,8 @@
4138 if (!light.firstChildElement("maximum").isNull()) {
4139 max = WWidget::selectNodeFloat(light, "maximum");
4140 }
4141- qDebug() << "Creating LED handler hook for:" << group << key << "between"<< min << "and" << max << "to midi out:" << status << midino << "on" << device << "on/off:" << on << off;
4142- allhandlers.append(new MidiLedHandler(group, key, midi, min, max, status, midino, device, on, off));
4143+ qDebug() << "Creating LED handler hook for:" << group << key << "between"<< min << "and" << max << "to midi out:" << status << midino << "on/off:" << on << off;
4144+ allhandlers.append(new MidiLedHandler(group, key, midi, min, max, status, midino, on, off));
4145 }
4146 light = light.nextSibling();
4147 }
4148
4149=== renamed file 'mixxx/src/midiledhandler.h' => 'mixxx/src/midi/midiledhandler.h'
4150--- mixxx/src/midiledhandler.h 2009-04-19 18:54:16 +0000
4151+++ mixxx/src/midi/midiledhandler.h 2009-11-10 00:33:17 +0000
4152@@ -5,7 +5,7 @@
4153 #define MIDILEDHANDLER_H
4154
4155 #include "controlobject.h"
4156-#include "midiobject.h"
4157+#include "mididevice.h"
4158
4159 #include <q3ptrlist.h>
4160
4161@@ -13,11 +13,11 @@
4162 {
4163 Q_OBJECT
4164 public:
4165- MidiLedHandler(QString group, QString key, MidiObject& midi, double min, double max,
4166- unsigned char status, unsigned char midino, QString device, unsigned char on, unsigned char off);
4167+ MidiLedHandler(QString group, QString key, MidiDevice & midi, double min, double max,
4168+ unsigned char status, unsigned char midino, unsigned char on, unsigned char off);
4169 ~MidiLedHandler();
4170
4171- static void createHandlers(QDomNode node, MidiObject& midi, QString device);
4172+ static void createHandlers(QDomNode node, MidiDevice & midi);
4173 static void destroyHandlers();
4174 static Q3PtrList<MidiLedHandler> allhandlers;
4175
4176@@ -25,13 +25,12 @@
4177 void controlChanged(double value);
4178
4179 private:
4180- MidiObject& m_midi;
4181+ MidiDevice& m_midi;
4182 double m_min;
4183 double m_max;
4184 ControlObject* m_cobj;
4185 unsigned char m_status;
4186 unsigned char m_midino;
4187- QString m_device;
4188 unsigned char m_on;
4189 unsigned char m_off;
4190 unsigned char lastStatus;
4191
4192=== renamed file 'mixxx/src/midimapping.cpp' => 'mixxx/src/midi/midimapping.cpp'
4193--- mixxx/src/midimapping.cpp 2009-11-10 00:33:14 +0000
4194+++ mixxx/src/midi/midimapping.cpp 2009-11-10 00:33:17 +0000
4195@@ -4,6 +4,7 @@
4196 -------------------
4197 begin : Sat Jan 17 2009
4198 copyright : (C) 2009 Sean M. Pappalardo
4199+ (C) 2009 Albert Santoni
4200 email : pegasus@c64.org
4201
4202 ***************************************************************************/
4203@@ -22,40 +23,139 @@
4204 #include "widget/wwidget.h" // FIXME: This should be xmlparse.h
4205 #include "mixxxcontrol.h"
4206 #include "midimessage.h"
4207+#include "defs.h"
4208 #include "midiinputmappingtablemodel.h"
4209 #include "midioutputmappingtablemodel.h"
4210 #include "midimapping.h"
4211+#include "mididevicedummy.h"
4212 #include "midiledhandler.h"
4213 #include "configobject.h"
4214
4215-#define REQUIRED_MAPPING_FILE "midi-mappings-scripts.js"
4216+#define REQUIRED_SCRIPT_FILE "midi-mappings-scripts.js"
4217 #define XML_SCHEMA_VERSION "1"
4218+#define DEFAULT_DEVICE_PRESET BINDINGS_PATH.append(m_deviceName.right(m_deviceName.size()-m_deviceName.indexOf(" ")-1).replace(" ", "_") + MIDI_MAPPING_EXTENSION)
4219
4220 static QString toHex(QString numberStr) {
4221 return "0x" + QString("0" + QString::number(numberStr.toUShort(), 16).toUpper()).right(2);
4222 }
4223
4224-MidiMapping::MidiMapping(MidiObject& midi_object) : QObject(), m_rMidiObject(midi_object), m_mappingLock(QMutex::Recursive) {
4225+MidiMapping::MidiMapping(MidiDevice* outputMidiDevice)
4226+ : QObject(),
4227+ m_mappingLock(QMutex::Recursive) {
4228+ // If BINDINGS_PATH doesn't exist, create it
4229+ if (!QDir(BINDINGS_PATH).exists()) {
4230+ qDebug() << "Creating new MIDI presets directory" << BINDINGS_PATH;
4231+ QDir().mkpath(BINDINGS_PATH);
4232+ }
4233+
4234+ //Q_ASSERT(outputMidiDevice);
4235+
4236 #ifdef __MIDISCRIPT__
4237- m_pScriptEngine = midi_object.getMidiScriptEngine();
4238+ //Start the scripting engine.
4239+ m_pScriptEngine = NULL;
4240+ m_pOutputMidiDevice = outputMidiDevice;
4241+ if (m_pOutputMidiDevice)
4242+ m_deviceName = m_pOutputMidiDevice->getName(); //Name of the device to look for the <controller> block for in the XML.
4243+
4244+ startupScriptEngine();
4245 #endif
4246 m_pMidiInputMappingTableModel = new MidiInputMappingTableModel(this);
4247 m_pMidiOutputMappingTableModel = new MidiOutputMappingTableModel(this);
4248 }
4249
4250 MidiMapping::~MidiMapping() {
4251-#ifdef __MIDISCRIPT__
4252- // Call each script's shutdown function if it exists
4253- QListIterator<QString> prefixIt(m_pScriptFunctionPrefixes);
4254- while (prefixIt.hasNext()) {
4255- QString shutName = prefixIt.next();
4256- if (shutName!="") {
4257- shutName.append(".shutdown");
4258- qDebug() << "MidiMapping: Executing" << shutName;
4259- if (!m_pScriptEngine->execute(shutName))
4260- qWarning() << "MidiMapping: No" << shutName << "function in script";
4261- }
4262- }
4263+
4264+}
4265+
4266+#ifdef __MIDISCRIPT__
4267+void MidiMapping::startupScriptEngine() {
4268+
4269+ if(m_pScriptEngine) return;
4270+
4271+ //XXX Deadly hack attack:
4272+ if (m_pOutputMidiDevice == NULL) {
4273+ m_pOutputMidiDevice = new MidiDeviceDummy(this); //Just make some dummy device :(
4274+ }
4275+ //XXX Memory leak :(
4276+
4277+ qDebug () << "Starting script engine with output device" << m_pOutputMidiDevice->getName();
4278+
4279+ m_pScriptEngine = new MidiScriptEngine(m_pOutputMidiDevice);
4280+
4281+ m_pScriptEngine->moveToThread(m_pScriptEngine);
4282+
4283+ connect(m_pScriptEngine, SIGNAL(initialized()),
4284+ this, SLOT(slotScriptEngineReady()),
4285+ Qt::DirectConnection);
4286+ m_scriptEngineInitializedMutex.lock();
4287+ m_pScriptEngine->start();
4288+ // Wait until the script engine is initialized
4289+ m_scriptEngineInitializedCondition.wait(&m_scriptEngineInitializedMutex);
4290+ m_scriptEngineInitializedMutex.unlock();
4291+
4292+}
4293+
4294+void MidiMapping::loadScriptCode() {
4295+ ConfigObject<ConfigValue> *config = new ConfigObject<ConfigValue>(QDir::homePath().append("/").append(SETTINGS_PATH).append(SETTINGS_FILE));
4296+
4297+ qDebug() << "MidiMapping: Loading & evaluating all MIDI script code";
4298+
4299+ QListIterator<QString> it(m_pScriptFileNames);
4300+ while (it.hasNext()) {
4301+ QString curScriptFileName = it.next();
4302+ m_pScriptEngine->evaluate(config->getConfigPath().append("midi/").append(curScriptFileName));
4303+
4304+ if(m_pScriptEngine->hasErrors(curScriptFileName)) {
4305+ qDebug() << "Errors occured while loading " << curScriptFileName;
4306+ }
4307+ }
4308+}
4309+
4310+void MidiMapping::initializeScripts() {
4311+ if(m_pScriptEngine) {
4312+ // Call each script's init function if it exists
4313+ QListIterator<QString> prefixIt(m_pScriptFunctionPrefixes);
4314+ while (prefixIt.hasNext()) {
4315+ QString initName = prefixIt.next();
4316+ if (initName!="") {
4317+ initName.append(".init");
4318+ qDebug() << "MidiMapping: Executing" << initName;
4319+ if (!m_pScriptEngine->execute(initName, m_deviceName))
4320+ qWarning() << "MidiMapping: No" << initName << "function in script";
4321+ }
4322+ }
4323+ }
4324+}
4325+
4326+void MidiMapping::shutdownScriptEngine() {
4327+ if(m_pScriptEngine) {
4328+ // Call each script's shutdown function if it exists
4329+ QListIterator<QString> prefixIt(m_pScriptFunctionPrefixes);
4330+ while (prefixIt.hasNext()) {
4331+ QString shutName = prefixIt.next();
4332+ if (shutName!="") {
4333+ shutName.append(".shutdown");
4334+ qDebug() << "MidiMapping: Executing" << shutName;
4335+ if (!m_pScriptEngine->execute(shutName))
4336+ qWarning() << "MidiMapping: No" << shutName << "function in script";
4337+ }
4338+ }
4339+ qDebug() << "MidiMapping: Deleting MIDI script engine...";
4340+ MidiScriptEngine *engine = m_pScriptEngine;
4341+ m_pScriptEngine = NULL;
4342+ delete engine;
4343+ }
4344+}
4345+#endif
4346+
4347+void MidiMapping::setOutputMidiDevice(MidiDevice* outputMidiDevice)
4348+{
4349+ m_mappingLock.lock();
4350+ m_pOutputMidiDevice = outputMidiDevice;
4351+ m_mappingLock.unlock();
4352+#ifdef __MIDISCRIPT__
4353+ //Restart the script engine so it gets its pointer to the output MIDI device updated.
4354+ restartScriptEngine();
4355 #endif
4356 }
4357
4358@@ -384,34 +484,41 @@
4359 }
4360 #endif
4361
4362-/* loadInitialPreset()
4363- * Loads a set of MIDI bindings from either the default file or one specified on the command line.
4364+/* setName(QString)
4365+ * Sets the controller name this mapping corresponds to
4366+ * @param name The controller name this mapping is hooked to
4367 */
4368-void MidiMapping::loadInitialPreset() {
4369- // Try to read in the current XML bindings file, one from the command line, or create one if nothing is available
4370- QStringList commandLineArgs = QApplication::arguments();
4371- int loadXML = commandLineArgs.indexOf("--loadXMLfile");
4372+void MidiMapping::setName(QString name) {
4373+ m_deviceName = name;
4374+}
4375
4376- if (loadXML!=-1) {
4377- qDebug() << "MidiMapping: Loading custom MIDI mapping file:" << commandLineArgs.at(loadXML+1);
4378- loadPreset(commandLineArgs.at(loadXML+1));
4379- }
4380- else loadPreset(BINDINGS_PATH);
4381- applyPreset();
4382+/* loadPreset()
4383+ * Overloaded function for convenience, uses the default device path
4384+ * @param forceLoad Forces the MIDI mapping to be loaded, regardless of whether or not the controller id
4385+ * specified in the mapping matches the device this MidiMapping object is hooked up to.
4386+ */
4387+void MidiMapping::loadPreset(bool forceLoad) {
4388+ loadPreset(DEFAULT_DEVICE_PRESET, forceLoad);
4389 }
4390
4391 /* loadPreset(QString)
4392 * Overloaded function for convenience
4393+ * @param path The path to a MIDI mapping XML file.
4394+ * @param forceLoad Forces the MIDI mapping to be loaded, regardless of whether or not the controller id
4395+ * specified in the mapping matches the device this MidiMapping object is hooked up to.
4396 */
4397-void MidiMapping::loadPreset(QString path) {
4398- qDebug() << "MidiMapping: Loading MIDI XML from" << path;
4399- loadPreset(WWidget::openXMLFile(path, "controller"));
4400+void MidiMapping::loadPreset(QString path, bool forceLoad) {
4401+ qDebug() << "MidiMapping: Loading MIDI preset from" << path;
4402+ loadPreset(WWidget::openXMLFile(path, "controller"), forceLoad);
4403 }
4404
4405 /* loadPreset(QDomElement)
4406 * Loads a set of MIDI bindings from a QDomElement structure.
4407+ * @param root The root node of the XML document for the MIDI mapping.
4408+ * @param forceLoad Forces the MIDI mapping to be loaded, regardless of whether or not the controller id
4409+ * specified in the mapping matches the device this MidiMapping object is hooked up to.
4410 */
4411-void MidiMapping::loadPreset(QDomElement root) {
4412+void MidiMapping::loadPreset(QDomElement root, bool forceLoad) {
4413 //qDebug() << QString("MidiMapping: loadPreset() called in thread ID=%1").arg(this->thread()->currentThreadId(),0,16);
4414
4415 if (root.isNull()) return;
4416@@ -426,8 +533,6 @@
4417 m_mappingLock.lock();
4418
4419 #ifdef __MIDISCRIPT__
4420- m_rMidiObject.restartScriptEngine();
4421- m_pScriptEngine = m_rMidiObject.getMidiScriptEngine();
4422 m_pScriptFileNames.clear();
4423 m_pScriptFunctionPrefixes.clear();
4424 #endif
4425@@ -435,19 +540,31 @@
4426 // For each controller in the DOM
4427 m_Bindings = root;
4428 QDomElement controller = m_Bindings.firstChildElement("controller");
4429+
4430+ // For each controller in the MIDI mapping XML...
4431+ //(Only parse the <controller> block if it's id matches our device name, otherwise
4432+ //keep looking at the next controller blocks....)
4433+ QString device;
4434 while (!controller.isNull()) {
4435- // For each controller
4436 // Get deviceid
4437- QString device = controller.attribute("id","");
4438- qDebug() << device << " settings found" << endl;
4439-
4440+ device = controller.attribute("id","");
4441+ if (device != m_deviceName && !forceLoad) {
4442+ controller = controller.nextSiblingElement("controller");
4443+ }
4444+ else
4445+ break;
4446+ }
4447+
4448+ if (!controller.isNull()) {
4449+
4450+ qDebug() << device << " settings found";
4451 #ifdef __MIDISCRIPT__
4452+ // Build a list of MIDI script files to load
4453
4454- // Get a list of MIDI script files to load
4455 QDomElement scriptFile = controller.firstChildElement("scriptfiles").firstChildElement("file");
4456
4457 // Default currently required file
4458- addScriptFile(REQUIRED_MAPPING_FILE,"");
4459+ addScriptFile(REQUIRED_SCRIPT_FILE,"");
4460
4461 // Look for additional ones
4462 while (!scriptFile.isNull()) {
4463@@ -458,33 +575,7 @@
4464 scriptFile = scriptFile.nextSiblingElement("file");
4465 }
4466
4467- // Load Script files
4468- ConfigObject<ConfigValue> *config = new ConfigObject<ConfigValue>(QDir::homePath().append("/").append(SETTINGS_PATH).append(SETTINGS_FILE));
4469-
4470- qDebug() << "MidiMapping: Loading & evaluating all MIDI script code";
4471-
4472- QListIterator<QString> it(m_pScriptFileNames);
4473- while (it.hasNext()) {
4474- QString curScriptFileName = it.next();
4475- m_pScriptEngine->evaluate(config->getConfigPath().append("midi/").append(curScriptFileName));
4476-
4477- if(m_pScriptEngine->hasErrors(curScriptFileName)) {
4478- qDebug() << "Errors occured while loading " << curScriptFileName;
4479- }
4480-
4481- }
4482-
4483- // Call each script's init function if it exists
4484- QListIterator<QString> prefixIt(m_pScriptFunctionPrefixes);
4485- while (prefixIt.hasNext()) {
4486- QString initName = prefixIt.next();
4487- if (initName!="") {
4488- initName.append(".init");
4489- qDebug() << "MidiMapping: Executing" << initName;
4490- if (!m_pScriptEngine->execute(initName, device))
4491- qWarning() << "MidiMapping: No" << initName << "function in script";
4492- }
4493- }
4494+ loadScriptCode(); // Actually load code from the list built above
4495
4496 QStringList scriptFunctions = m_pScriptEngine->getScriptFunctions();
4497
4498@@ -543,25 +634,33 @@
4499 }
4500
4501 qDebug() << "MidiMapping: Output parsed!";
4502- controller = controller.nextSiblingElement("controller");
4503+ //controller = controller.nextSiblingElement("controller"); //FIXME: Remove this line of code permanently - Albert
4504 }
4505
4506 m_mappingLock.unlock();
4507
4508 } // END loadPreset(QDomElement)
4509
4510+/* savePreset()
4511+ * Saves the current table of bindings to the default device XML file.
4512+ */
4513+void MidiMapping::savePreset() {
4514+ savePreset(DEFAULT_DEVICE_PRESET);
4515+}
4516+
4517 /* savePreset(QString)
4518 * Given a path, saves the current table of bindings to an XML file.
4519 */
4520 void MidiMapping::savePreset(QString path) {
4521+ qDebug() << "Writing MIDI preset file" << path;
4522 m_mappingLock.lock();
4523 QFile output(path);
4524 if (!output.open(QIODevice::WriteOnly | QIODevice::Truncate)) return;
4525 QTextStream outputstream(&output);
4526 // Construct the DOM from the table
4527- buildDomElement();
4528+ QDomDocument docBindings = buildDomElement();
4529 // Save the DOM to the XML file
4530- m_Bindings.save(outputstream, 4);
4531+ docBindings.save(outputstream, 4);
4532 output.close();
4533 m_mappingLock.unlock();
4534 }
4535@@ -571,21 +670,36 @@
4536 * the LED handler.
4537 */
4538 void MidiMapping::applyPreset() {
4539+ qDebug() << "MidiMapping::applyPreset()";
4540 m_mappingLock.lock();
4541 MidiLedHandler::destroyHandlers();
4542
4543- QDomElement controller = m_Bindings.firstChildElement("controller");
4544- // For each device
4545- while (!controller.isNull()) {
4546- // Device Outputs - LEDs
4547- QString deviceId = controller.attribute("id","");
4548-
4549- qDebug() << "MidiMapping: Processing MIDI Output Bindings for" << deviceId;
4550- MidiLedHandler::createHandlers(controller.namedItem("outputs").firstChild(),
4551- m_rMidiObject, deviceId);
4552-
4553- // Next device
4554- controller = controller.nextSiblingElement("controller");
4555+#ifdef __MIDISCRIPT__
4556+ // Since this can be called after re-enabling a device without reloading the XML preset,
4557+ // the script engine must have its code loaded here as well
4558+ QStringList scriptFunctions = m_pScriptEngine->getScriptFunctions();
4559+ if (scriptFunctions.isEmpty()) loadScriptCode();
4560+
4561+ initializeScripts();
4562+#endif
4563+
4564+ if (m_pOutputMidiDevice != NULL) {
4565+ //^^^ Only execute this code if we have an output device hooked up
4566+ // to this MidiMapping...
4567+
4568+ QDomElement controller = m_Bindings.firstChildElement("controller");
4569+ // For each device
4570+ while (!controller.isNull()) {
4571+ // Device Outputs - LEDs
4572+ QString deviceId = controller.attribute("id","");
4573+
4574+ qDebug() << "MidiMapping: Processing MIDI Output Bindings for" << deviceId;
4575+ MidiLedHandler::createHandlers(controller.namedItem("outputs").firstChild(),
4576+ *m_pOutputMidiDevice);
4577+
4578+ // Next device
4579+ controller = controller.nextSiblingElement("controller");
4580+ }
4581 }
4582 m_mappingLock.unlock();
4583 }
4584@@ -606,69 +720,96 @@
4585 /* buildDomElement()
4586 * Updates the DOM with what is currently in the table
4587 */
4588- void MidiMapping::buildDomElement() {
4589- // We should hold the mapping lock.
4590-
4591- clearPreset(); // Create blank document
4592-
4593- const QString wtfbbqdevicename = "Last used";
4594+ QDomDocument MidiMapping::buildDomElement() {
4595+ // We should hold the mapping lock. The lock is recursive so if we already
4596+ // hold it it will relock.
4597+ m_mappingLock.lock();
4598+
4599+ clearPreset(); // Create blank document
4600+
4601+ QDomDocument doc("Bindings");
4602+ QString blank = "<MixxxMIDIPreset schemaVersion=\"" + QString(XML_SCHEMA_VERSION) + "\" mixxxVersion=\"" + QString(VERSION) + "+\">\n"
4603+ "</MixxxMIDIPreset>\n";
4604+
4605+ doc.setContent(blank);
4606+
4607+ QDomElement rootNode = doc.documentElement();
4608+ QDomElement controller = doc.createElement("controller");
4609+ controller.setAttribute("id", m_deviceName.right(m_deviceName.size()-m_deviceName.indexOf(" ")-1));
4610+ rootNode.appendChild(controller);
4611+
4612 #ifdef __MIDISCRIPT__
4613- //This sucks, put this code inside MidiScriptEngine instead of here,
4614- // and just ask MidiScriptEngine to spit it out for us.
4615- qDebug() << "MidiMapping: Writing script block!";
4616- for (int i = 0; i < m_pScriptFileNames.count(); i++) {
4617- qDebug() << "MidiMapping: writing script block for" << m_pScriptFileNames[i];
4618- QString filename = m_pScriptFileNames[i];
4619- if (filename != REQUIRED_MAPPING_FILE) { //Don't need to write anything for the required mapping file.
4620- QString functionPrefix = m_pScriptFunctionPrefixes[i];
4621- //and now for the worst XML code since... WWidget...
4622- QDomDocument sucksBalls;
4623- QDomElement scriptFile = sucksBalls.createElement("file");
4624- scriptFile.setAttribute("filename", filename);
4625- scriptFile.setAttribute("functionprefix", functionPrefix);
4626-
4627- //Add the XML dom element to the right spot in the XML document.
4628- addMidiScriptInfo(scriptFile, wtfbbqdevicename);
4629- }
4630- }
4631+ //This sucks, put this code inside MidiScriptEngine instead of here,
4632+ // and just ask MidiScriptEngine to spit it out for us.
4633+// qDebug() << "MidiMapping: Writing script block!";
4634+
4635+ QDomElement scriptFiles = doc.createElement("scriptfiles");
4636+ controller.appendChild(scriptFiles);
4637+
4638+
4639+ for (int i = 0; i < m_pScriptFileNames.count(); i++) {
4640+// qDebug() << "MidiMapping: writing script block for" << m_pScriptFileNames[i];
4641+ QString filename = m_pScriptFileNames[i];
4642+
4643+
4644+ //Don't need to write anything for the required mapping file.
4645+ if (filename != REQUIRED_SCRIPT_FILE) {
4646+ qDebug() << "MidiMapping: writing script block for" << filename;
4647+ QString functionPrefix = m_pScriptFunctionPrefixes[i];
4648+ QDomElement scriptFile = doc.createElement("file");
4649+
4650+
4651+ scriptFile.setAttribute("filename", filename);
4652+ scriptFile.setAttribute("functionprefix", functionPrefix);
4653+
4654+ scriptFiles.appendChild(scriptFile);
4655+ }
4656+ }
4657 #endif
4658
4659+ QDomElement controls = doc.createElement("controls");
4660+ controller.appendChild(controls);
4661+
4662+
4663 //Iterate over all of the command/control pairs in the input mapping
4664- QHashIterator<MidiMessage, MixxxControl> it(m_inputMapping);
4665- while (it.hasNext()) {
4666- it.next();
4667- QDomElement controlNode;
4668- QDomDocument nodeMaker;
4669-
4670- //Create <control> block
4671- controlNode = nodeMaker.createElement("control");
4672-
4673- //Save the MidiMessage and MixxxControl objects as XML
4674- it.key().serializeToXML(controlNode);
4675- it.value().serializeToXML(controlNode);
4676-
4677- //Add the control node we just created to the XML document in the proper spot
4678- addControl(controlNode, wtfbbqdevicename); //FIXME: Remove this device shit until we have multiple device support.
4679- }
4680-
4681- //Iterate over all of the control/command pairs in the OUTPUT mapping
4682- QHashIterator<MixxxControl, MidiMessage> outIt(m_outputMapping);
4683- while (outIt.hasNext()) {
4684- outIt.next();
4685- QDomElement outputNode;
4686- QDomDocument nodeMaker;
4687-
4688- //Create <output> block
4689- outputNode = nodeMaker.createElement("output");
4690-
4691- //Save the MidiMessage and MixxxControl objects as XML
4692- outIt.key().serializeToXML(outputNode, true);
4693- outIt.value().serializeToXML(outputNode, true);
4694-
4695- //Add the control node we just created to the XML document in the proper spot
4696- addOutput(outputNode, wtfbbqdevicename); //FIXME: Remove this device shit until we have multiple device support.
4697- }
4698- }
4699+ QHashIterator<MidiMessage, MixxxControl> it(m_inputMapping);
4700+ while (it.hasNext()) {
4701+ it.next();
4702+
4703+ QDomElement controlNode = doc.createElement("control");
4704+
4705+ //Save the MidiMessage and MixxxControl objects as XML
4706+ it.key().serializeToXML(controlNode);
4707+ it.value().serializeToXML(controlNode);
4708+
4709+ //Add the control node we just created to the XML document in the proper spot
4710+ controls.appendChild(controlNode);
4711+ }
4712+
4713+
4714+ QDomElement outputs = doc.createElement("outputs");
4715+ controller.appendChild(outputs);
4716+
4717+ //Iterate over all of the control/command pairs in the OUTPUT mapping
4718+ QHashIterator<MixxxControl, MidiMessage> outIt(m_outputMapping);
4719+ while (outIt.hasNext()) {
4720+ outIt.next();
4721+
4722+ QDomElement outputNode = doc.createElement("output");
4723+
4724+
4725+ //Save the MidiMessage and MixxxControl objects as XML
4726+ outIt.key().serializeToXML(outputNode, true);
4727+ outIt.value().serializeToXML(outputNode, true);
4728+
4729+ //Add the control node we just created to the XML document in the proper spot
4730+ outputs.appendChild(outputNode);
4731+ }
4732+
4733+ m_mappingLock.unlock();
4734+
4735+ return doc;
4736+}
4737
4738 /* -------- ------------------------------------------------------
4739 Purpose: Adds an input MIDI mapping block to the XML.
4740@@ -954,3 +1095,23 @@
4741 m_controlToLearn = MixxxControl();
4742 m_mappingLock.unlock();
4743 }
4744+
4745+#ifdef __MIDISCRIPT__
4746+void MidiMapping::restartScriptEngine()
4747+{
4748+ shutdownScriptEngine();
4749+ startupScriptEngine();
4750+}
4751+#endif
4752+
4753+void MidiMapping::slotScriptEngineReady() {
4754+#ifdef __MIDISCRIPT__ // Can't ifdef slots in the .h file, so we just do the body.
4755+
4756+ // The lock prevents us from waking before the main thread is waiting on the
4757+ // condition.
4758+ m_scriptEngineInitializedMutex.lock();
4759+ m_scriptEngineInitializedCondition.wakeAll();
4760+ m_scriptEngineInitializedMutex.unlock();
4761+
4762+#endif
4763+}
4764
4765=== renamed file 'mixxx/src/midimapping.h' => 'mixxx/src/midi/midimapping.h'
4766--- mixxx/src/midimapping.h 2009-07-15 02:32:40 +0000
4767+++ mixxx/src/midi/midimapping.h 2009-11-10 00:33:17 +0000
4768@@ -4,6 +4,7 @@
4769 -------------------
4770 begin : Sat Jan 17 2009
4771 copyright : (C) 2009 Sean M. Pappalardo
4772+ (C) 2009 Albert Santoni
4773 email : pegasus@c64.org
4774
4775 ***************************************************************************/
4776@@ -20,7 +21,7 @@
4777 #ifndef MIDIMAPPING_H
4778 #define MIDIMAPPING_H
4779
4780-#include "midiobject.h"
4781+#include "mididevice.h"
4782 #include "midimessage.h"
4783 #include "mixxxcontrol.h"
4784 #include "midiinputmapping.h"
4785@@ -28,14 +29,14 @@
4786 #include <QTableWidget>
4787
4788 #ifdef __MIDISCRIPT__
4789-#include "script/midiscriptengine.h"
4790+#include "midiscriptengine.h"
4791 #endif
4792
4793 //Forward declarations
4794 class MidiInputMappingTableModel;
4795 class MidiOutputMappingTableModel;
4796
4797-#define BINDINGS_PATH QDir::homePath().append("/").append(SETTINGS_PATH).append("MixxxMIDIBindings.xml")
4798+#define BINDINGS_PATH QDir::homePath().append("/").append(SETTINGS_PATH).append("midi/")
4799 #define MIDI_MAPPING_EXTENSION ".midi.xml"
4800
4801 class MidiMapping : public QObject
4802@@ -44,14 +45,18 @@
4803
4804 public:
4805 /** Constructor also loads & applies the default XML MIDI mapping file */
4806- MidiMapping(MidiObject &midi_object);
4807+ MidiMapping(MidiDevice* outputMidiDevice=NULL);
4808 ~MidiMapping();
4809-
4810- void loadInitialPreset();
4811- void loadPreset(QString path);
4812- void loadPreset(QDomElement root);
4813-
4814- void savePreset(QString path = BINDINGS_PATH);
4815+ void setOutputMidiDevice(MidiDevice* outputMidiDevice);
4816+
4817+ void setName(QString name);
4818+
4819+ void loadPreset(bool forceLoad=false);
4820+ void loadPreset(QString path, bool forceLoad=false);
4821+ void loadPreset(QDomElement root, bool forceLoad=false);
4822+
4823+ void savePreset();
4824+ void savePreset(QString path);
4825 void applyPreset();
4826
4827
4828@@ -87,12 +92,20 @@
4829 void clearOutputMidiMapping(int index);
4830 void clearOutputMidiMapping(MixxxControl control);
4831 void clearOutputMidiMapping(int index, int count);
4832+#ifdef __MIDISCRIPT__
4833+ void initializeScripts();
4834+ void startupScriptEngine();
4835+ void shutdownScriptEngine();
4836+ void restartScriptEngine();
4837+ MidiScriptEngine *getMidiScriptEngine() { return m_pScriptEngine; };
4838+#endif
4839
4840 public slots:
4841 void finishMidiLearn(MidiMessage message);
4842 void beginMidiLearn(MixxxControl control);
4843 void cancelMidiLearn();
4844-
4845+ void slotScriptEngineReady();
4846+
4847 signals:
4848 void inputMappingChanged();
4849 void inputMappingChanged(int startIndex, int endIndex);
4850@@ -115,7 +128,7 @@
4851 MidiMessage command,
4852 bool shouldEmit);
4853 void clearPreset();
4854- void buildDomElement();
4855+ QDomDocument buildDomElement();
4856 void addControl(QDomElement& control, QString device);
4857 void addOutput(QDomElement& output, QString device);
4858 void addMidiScriptInfo(QDomElement &scriptFile, QString device); //Sucks
4859@@ -129,19 +142,27 @@
4860 #ifdef __MIDISCRIPT__
4861 /** Adds a script file name and function prefix to the list to be loaded */
4862 void addScriptFile(QString filename, QString functionprefix);
4863+ /** Actually loads script code from the files in the list */
4864+ void loadScriptCode();
4865
4866 QList<QString> m_pScriptFileNames;
4867 QList<QString> m_pScriptFunctionPrefixes;
4868 MidiScriptEngine *m_pScriptEngine;
4869+
4870+ QMutex m_scriptEngineInitializedMutex;
4871+ QWaitCondition m_scriptEngineInitializedCondition;
4872 #endif
4873 QMutex m_mappingLock;
4874 QDomElement m_Bindings;
4875- MidiObject &m_rMidiObject;
4876 MidiInputMapping m_inputMapping;
4877 MidiOutputMapping m_outputMapping;
4878 MidiInputMappingTableModel* m_pMidiInputMappingTableModel;
4879 MidiOutputMappingTableModel* m_pMidiOutputMappingTableModel;
4880 MixxxControl m_controlToLearn;
4881+ QString m_deviceName; /** Name of the device to look for in the <controller> XML nodes... */
4882+ MidiDevice* m_pOutputMidiDevice; /** We need a pointer back to an _output_ MIDI device so our
4883+ LED handlers know where to fire MIDI messages. Note that
4884+ this can be NULL if there is no output MIDI device! */
4885 };
4886
4887 #endif
4888
4889=== renamed file 'mixxx/src/midimessage.cpp' => 'mixxx/src/midi/midimessage.cpp'
4890=== renamed file 'mixxx/src/midimessage.h' => 'mixxx/src/midi/midimessage.h'
4891--- mixxx/src/midimessage.h 2009-04-19 17:25:23 +0000
4892+++ mixxx/src/midi/midimessage.h 2009-11-10 00:33:17 +0000
4893@@ -16,6 +16,18 @@
4894 MIDI_STATUS_PITCH_BEND = 0xE0,
4895 } MidiStatusByte;
4896
4897+ // This enum is used in the decoding of the status message into voice categories
4898+// This is just cruft leftover from ages ago, unfortunately. Hasn't been properly removed/refactored yet.
4899+typedef enum {
4900+ NOTE_OFF = 0x80,
4901+ NOTE_ON = 0x90,
4902+ AFTERTOUCH = 0xA0,
4903+ CTRL_CHANGE = 0xB0,
4904+ PROG_CHANGE = 0xC0,
4905+ CHANNEL_PRESSURE = 0xD0,
4906+ PITCH_WHEEL = 0xE0,
4907+} MidiCategory;
4908+
4909 /** The key used in the MIDI mapping hash table */
4910 class MidiMessage
4911 {
4912
4913=== renamed file 'mixxx/src/midinodelegate.cpp' => 'mixxx/src/midi/midinodelegate.cpp'
4914=== renamed file 'mixxx/src/midinodelegate.h' => 'mixxx/src/midi/midinodelegate.h'
4915=== renamed file 'mixxx/src/midioptiondelegate.cpp' => 'mixxx/src/midi/midioptiondelegate.cpp'
4916=== renamed file 'mixxx/src/midioptiondelegate.h' => 'mixxx/src/midi/midioptiondelegate.h'
4917=== renamed file 'mixxx/src/midioutputmapping.h' => 'mixxx/src/midi/midioutputmapping.h'
4918=== renamed file 'mixxx/src/midioutputmappingtablemodel.cpp' => 'mixxx/src/midi/midioutputmappingtablemodel.cpp'
4919=== renamed file 'mixxx/src/midioutputmappingtablemodel.h' => 'mixxx/src/midi/midioutputmappingtablemodel.h'
4920=== renamed file 'mixxx/src/script/midiscriptengine.cpp' => 'mixxx/src/midi/midiscriptengine.cpp'
4921--- mixxx/src/script/midiscriptengine.cpp 2009-08-11 04:38:51 +0000
4922+++ mixxx/src/midi/midiscriptengine.cpp 2009-11-10 00:33:17 +0000
4923@@ -16,11 +16,11 @@
4924 * *
4925 ***************************************************************************/
4926
4927-#include <qapplication.h>
4928-
4929-#include "midiscriptengine.h"
4930 #include "controlobject.h"
4931 #include "controlobjectthread.h"
4932+#include "mididevice.h"
4933+#include "midiscriptengine.h"
4934+
4935
4936 #ifdef _MSC_VER
4937 #include <float.h> // for _isnan() on VC++
4938@@ -30,9 +30,9 @@
4939 #endif
4940
4941
4942-MidiScriptEngine::MidiScriptEngine(MidiObject* midi_object) :
4943+MidiScriptEngine::MidiScriptEngine(MidiDevice* midiDevice) :
4944 m_pEngine(NULL),
4945- m_pMidiObject(midi_object)
4946+ m_pMidiDevice(midiDevice)
4947 {
4948 }
4949
4950@@ -88,11 +88,13 @@
4951 //qDebug() << "MidiScriptEngine::run() m_pEngine->parent() is " << m_pEngine->parent();
4952 //qDebug() << "MidiScriptEngine::run() m_pEngine->thread() is " << m_pEngine->thread();
4953
4954+ qDebug() << "MIDI Device in script engine is:" << m_pMidiDevice->getName();
4955+
4956 // Make this MidiScriptEngine instance available to scripts as
4957 // 'engine'.
4958 QScriptValue engineGlobalObject = m_pEngine->globalObject();
4959 engineGlobalObject.setProperty("engine", m_pEngine->newQObject(this));
4960- engineGlobalObject.setProperty("midi", m_pEngine->newQObject(m_pMidiObject));
4961+ engineGlobalObject.setProperty("midi", m_pEngine->newQObject(m_pMidiDevice));
4962
4963 }
4964
4965@@ -162,9 +164,10 @@
4966 -------- ------------------------------------------------------ */
4967 bool MidiScriptEngine::execute(QString function, char channel,
4968 char control, char value,
4969- MidiStatusByte status) {
4970+ MidiStatusByte status,
4971+ QString group) {
4972 m_scriptEngineLock.lock();
4973- bool ret = safeExecute(function, channel, control, value, status);
4974+ bool ret = safeExecute(function, channel, control, value, status, group);
4975 m_scriptEngineLock.unlock();
4976 return ret;
4977 }
4978@@ -237,7 +240,8 @@
4979 -------- ------------------------------------------------------ */
4980 bool MidiScriptEngine::safeExecute(QString function, char channel,
4981 char control, char value,
4982- MidiStatusByte status) {
4983+ MidiStatusByte status,
4984+ QString group) {
4985 //qDebug() << QString("MidiScriptEngine: Exec2 Thread ID=%1").arg(QThread::currentThreadId(),0,16);
4986
4987 if(m_pEngine == NULL) {
4988@@ -261,6 +265,7 @@
4989 args << QScriptValue(m_pEngine, control);
4990 args << QScriptValue(m_pEngine, value);
4991 args << QScriptValue(m_pEngine, status);
4992+ args << QScriptValue(m_pEngine, group);
4993
4994 scriptFunction.call(QScriptValue(), args);
4995 if (checkException())
4996@@ -338,7 +343,7 @@
4997
4998 if (line.indexOf('#') != 0 && line.indexOf("//") != 0) { // ignore commented out lines
4999 QStringList field = line.split(" ");
5000- qDebug() << "MidiScriptEngine: Found function:" << field[0] << "at line" << position;
The diff has been truncated for viewing.