diff options
author | crogers@google.com <crogers@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-22 02:08:15 +0000 |
---|---|---|
committer | crogers@google.com <crogers@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-22 02:08:15 +0000 |
commit | 5f6f9bce342075bea590cb69914d97eb3bdde29a (patch) | |
tree | a10c77431a369a15188a0e9fd3a89adc1ff0dbc8 /media/midi | |
parent | 68db1854c53776b1c97f6da4ad5d95d8803371ae (diff) | |
download | chromium_src-5f6f9bce342075bea590cb69914d97eb3bdde29a.zip chromium_src-5f6f9bce342075bea590cb69914d97eb3bdde29a.tar.gz chromium_src-5f6f9bce342075bea590cb69914d97eb3bdde29a.tar.bz2 |
don't include iostream.h
use ChildThread for main loop - fix Android build
whitespace fix
minor style fix
last minute compile fixes
address Antoine's comments
minor changes to reflect latest Blink API -- address palmer comments
last minute include order fix
address last minute style nits
stub out other OSes
support Takashi's MIDIAccessor
fix minor build err
undo param traits changes
get rid of param_traits - other minor style nits
address scherkus comments
use int64 for ParamTraits
WIP fix white-space issues more style basically working some cleanup -- support for multiple clients forgot midi_manager.cc Get MIDI port information sent to renderer formatting fixes lots of cleanup - added RequestAccess and Send style more style only bother sending received messages to renderer if approval was asked early steps to granting permission to Blink some progress to sending port info to Blink send client_id when requesting access fix minor style issues in .gyp files fix context/browser DEPS fix include paths
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@207992 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media/midi')
-rw-r--r-- | media/midi/midi_manager.cc | 67 | ||||
-rw-r--r-- | media/midi/midi_manager.h | 109 | ||||
-rw-r--r-- | media/midi/midi_manager_mac.cc | 205 | ||||
-rw-r--r-- | media/midi/midi_manager_mac.h | 69 | ||||
-rw-r--r-- | media/midi/midi_port_info.cc | 28 | ||||
-rw-r--r-- | media/midi/midi_port_info.h | 36 |
6 files changed, 514 insertions, 0 deletions
diff --git a/media/midi/midi_manager.cc b/media/midi/midi_manager.cc new file mode 100644 index 0000000..f991865 --- /dev/null +++ b/media/midi/midi_manager.cc @@ -0,0 +1,67 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "media/midi/midi_manager.h" + +namespace media { + +#if !defined(OS_MACOSX) +// TODO(crogers): implement MIDIManager for other platforms. +MIDIManager* MIDIManager::Create() { + return NULL; +} +#endif + +MIDIManager::MIDIManager() + : initialized_(false) { +} + +MIDIManager::~MIDIManager() {} + +bool MIDIManager::RequestAccess(MIDIManagerClient* client, int access) { + // TODO(crogers): determine if user prompt is necessary here. + // For now, simply don't allow sysex. + if (access != kNoSystemExclusive) + return false; + + // Lazily initialize the MIDI back-end. + if (!initialized_) + initialized_ = Initialize(); + + if (initialized_) { + base::AutoLock auto_lock(clients_lock_); + clients_.insert(client); + } + + return initialized_; +} + +void MIDIManager::ReleaseAccess(MIDIManagerClient* client) { + base::AutoLock auto_lock(clients_lock_); + ClientList::iterator i = clients_.find(client); + if (i != clients_.end()) + clients_.erase(i); +} + +void MIDIManager::AddInputPort(const MIDIPortInfo& info) { + input_ports_.push_back(info); +} + +void MIDIManager::AddOutputPort(const MIDIPortInfo& info) { + output_ports_.push_back(info); +} + +void MIDIManager::ReceiveMIDIData( + int port_index, + const uint8* data, + size_t length, + double timestamp) { + base::AutoLock auto_lock(clients_lock_); + + // TODO(crogers): Filter out sysex. + for (ClientList::iterator i = clients_.begin(); i != clients_.end(); ++i) + (*i)->ReceiveMIDIData(port_index, data, length, timestamp); +}; + +} // namespace media diff --git a/media/midi/midi_manager.h b/media/midi/midi_manager.h new file mode 100644 index 0000000..1df444f --- /dev/null +++ b/media/midi/midi_manager.h @@ -0,0 +1,109 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_MIDI_MIDI_MANAGER_H_ +#define MEDIA_MIDI_MIDI_MANAGER_H_ + +#include <set> + +#include "base/basictypes.h" +#include "base/synchronization/lock.h" +#include "media/base/media_export.h" +#include "media/midi/midi_port_info.h" + +namespace media { + +// A MIDIManagerClient registers with the MIDIManager to receive MIDI data. +// See MIDIManager::RequestAccess() and MIDIManager::ReleaseAccess() +// for details. +class MEDIA_EXPORT MIDIManagerClient { + public: + virtual ~MIDIManagerClient() {} + + // ReceiveMIDIData() is called when MIDI data has been received from the + // MIDI system. + // |port_index| represents the specific input port from input_ports(). + // |data| represents a series of bytes encoding one or more MIDI messages. + // |length| is the number of bytes in |data|. + // |timestamp| is the time the data was received, in seconds. + virtual void ReceiveMIDIData(int port_index, + const uint8* data, + size_t length, + double timestamp) = 0; +}; + +// Manages access to all MIDI hardware. +class MEDIA_EXPORT MIDIManager { + public: + enum AccessType { + kNoSystemExclusive, + kSystemExclusive + }; + + static MIDIManager* Create(); + + MIDIManager(); + virtual ~MIDIManager(); + + // A client calls RequestAccess() to receive and send MIDI data. + // If access is approved, the MIDI system is lazily initialized + // and the client is registered to receive MIDI data. + // Returns |true| if access is approved. + bool RequestAccess(MIDIManagerClient* client, int access); + + // A client calls ReleaseAccess() to stop receiving MIDI data. + void ReleaseAccess(MIDIManagerClient* client); + + // SendMIDIData() sends one or more messages at the given time. + // |port_index| represents the specific output port from output_ports(). + // |data| represents a series of bytes encoding one or more MIDI messages. + // |length| is the number of bytes in |data|. + // |timestamp| is the time to send the data, in seconds. + virtual void SendMIDIData(int port_index, + const uint8* data, + size_t length, + double timestamp) = 0; + + // input_ports() is a list of MIDI ports for receiving MIDI data. + // Each individual port in this list can be identified by its + // integer index into this list. + const MIDIPortInfoList& input_ports() { return input_ports_; } + + // output_ports() is a list of MIDI ports for sending MIDI data. + // Each individual port in this list can be identified by its + // integer index into this list. + const MIDIPortInfoList& output_ports() { return output_ports_; } + + protected: + // Initializes the MIDI system, returning |true| on success. + virtual bool Initialize() = 0; + + void AddInputPort(const MIDIPortInfo& info); + void AddOutputPort(const MIDIPortInfo& info); + + // Dispatches to all clients. + void ReceiveMIDIData( + int port_index, + const uint8* data, + size_t length, + double timestamp); + + bool initialized_; + + // Keeps track of all clients who wish to receive MIDI data. + typedef std::set<MIDIManagerClient*> ClientList; + ClientList clients_; + + // Protects access to our clients. + base::Lock clients_lock_; + + MIDIPortInfoList input_ports_; + MIDIPortInfoList output_ports_; + + DISALLOW_COPY_AND_ASSIGN(MIDIManager); +}; + +} // namespace media + +#endif // MEDIA_MIDI_MIDI_MANAGER_H_ diff --git a/media/midi/midi_manager_mac.cc b/media/midi/midi_manager_mac.cc new file mode 100644 index 0000000..73df1fe --- /dev/null +++ b/media/midi/midi_manager_mac.cc @@ -0,0 +1,205 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "media/midi/midi_manager_mac.h" + +#include <iostream> +#include <string> + +#include "base/debug/trace_event.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/sys_string_conversions.h" +#include <CoreAudio/HostTime.h> + +using base::IntToString; +using base::SysCFStringRefToUTF8; +using std::string; + +namespace media { + +MIDIManager* MIDIManager::Create() { + return new MIDIManagerMac(); +} + +MIDIManagerMac::MIDIManagerMac() + : midi_client_(NULL), + coremidi_input_(NULL), + coremidi_output_(NULL), + packet_list_(NULL), + midi_packet_(NULL) { +} + +bool MIDIManagerMac::Initialize() { + TRACE_EVENT0("midi", "MIDIManagerMac::Initialize"); + + // CoreMIDI registration. + midi_client_ = NULL; + OSStatus result = MIDIClientCreate( + CFSTR("Google Chrome"), + NULL, + NULL, + &midi_client_); + + if (result != noErr) + return false; + + coremidi_input_ = NULL; + + // Create input and output port. + result = MIDIInputPortCreate( + midi_client_, + CFSTR("MIDI Input"), + ReadMidiDispatch, + this, + &coremidi_input_); + if (result != noErr) + return false; + + result = MIDIOutputPortCreate( + midi_client_, + CFSTR("MIDI Output"), + &coremidi_output_); + if (result != noErr) + return false; + + int destination_count = MIDIGetNumberOfDestinations(); + destinations_.reserve(destination_count); + + for (int i = 0; i < destination_count ; i++) { + MIDIEndpointRef destination = MIDIGetDestination(i); + + // Keep track of all destinations (known as outputs by the Web MIDI API). + // Cache to avoid any possible overhead in calling MIDIGetDestination(). + destinations_[i] = destination; + + MIDIPortInfo info = GetPortInfoFromEndpoint(destination); + AddOutputPort(info); + } + + // Open connections from all sources. + int source_count = MIDIGetNumberOfSources(); + + for (int i = 0; i < source_count; ++i) { + // Receive from all sources. + MIDIEndpointRef src = MIDIGetSource(i); + MIDIPortConnectSource(coremidi_input_, src, src); + + // Keep track of all sources (known as inputs in Web MIDI API terminology). + source_map_[src] = i; + + MIDIPortInfo info = GetPortInfoFromEndpoint(src); + AddInputPort(info); + } + + // TODO(crogers): Fix the memory management here! + packet_list_ = reinterpret_cast<MIDIPacketList*>(midi_buffer_); + midi_packet_ = MIDIPacketListInit(packet_list_); + + return true; +} + +MIDIManagerMac::~MIDIManagerMac() { + if (coremidi_input_) + MIDIPortDispose(coremidi_input_); + if (coremidi_output_) + MIDIPortDispose(coremidi_output_); +} + +void MIDIManagerMac::ReadMidiDispatch(const MIDIPacketList* packet_list, + void* read_proc_refcon, + void* src_conn_refcon) { + MIDIManagerMac* manager = static_cast<MIDIManagerMac*>(read_proc_refcon); + MIDIEndpointRef source = static_cast<MIDIEndpointRef>(src_conn_refcon); + + // Dispatch to class method. + manager->ReadMidi(source, packet_list); +} + +void MIDIManagerMac::ReadMidi(MIDIEndpointRef source, + const MIDIPacketList* packet_list) { + // Lookup the port index based on the source. + SourceMap::iterator j = source_map_.find(source); + if (j == source_map_.end()) + return; + int port_index = source_map_[source]; + + // Go through each packet and process separately. + for(size_t i = 0; i < packet_list->numPackets; i++) { + // Each packet contains MIDI data for one or more messages (like note-on). + const MIDIPacket &packet = packet_list->packet[i]; + double timestamp_seconds = MIDITimeStampToSeconds(packet.timeStamp); + + ReceiveMIDIData( + port_index, + packet.data, + packet.length, + timestamp_seconds); + } +} + +void MIDIManagerMac::SendMIDIData(int port_index, + const uint8* data, + size_t length, + double timestamp) { + // TODO(crogers): Filter out sysex. + + MIDITimeStamp coremidi_timestamp = SecondsToMIDITimeStamp(timestamp); + + midi_packet_ = MIDIPacketListAdd( + packet_list_, + kMaxPacketListSize, + midi_packet_, + coremidi_timestamp, + length, + data); + + // Lookup the destination based on the port index. + // TODO(crogers): re-factor |port_index| to use unsigned + // to avoid the need for this check. + if (port_index < 0 || + static_cast<size_t>(port_index) >= destinations_.size()) + return; + + MIDIEndpointRef destination = destinations_[port_index]; + + MIDISend(coremidi_output_, destination, packet_list_); + + // Re-initialize for next time. + midi_packet_ = MIDIPacketListInit(packet_list_); +} + +MIDIPortInfo MIDIManagerMac::GetPortInfoFromEndpoint( + MIDIEndpointRef endpoint) { + SInt32 id_number = 0; + MIDIObjectGetIntegerProperty(endpoint, kMIDIPropertyUniqueID, &id_number); + string id = IntToString(id_number); + + CFStringRef manufacturer_ref = NULL; + MIDIObjectGetStringProperty( + endpoint, kMIDIPropertyManufacturer, &manufacturer_ref); + string manufacturer = SysCFStringRefToUTF8(manufacturer_ref); + + CFStringRef name_ref = NULL; + MIDIObjectGetStringProperty(endpoint, kMIDIPropertyName, &name_ref); + string name = SysCFStringRefToUTF8(name_ref); + + SInt32 version_number = 0; + MIDIObjectGetIntegerProperty( + endpoint, kMIDIPropertyDriverVersion, &version_number); + string version = IntToString(version_number); + + return MIDIPortInfo(id, manufacturer, name, version); +} + +double MIDIManagerMac::MIDITimeStampToSeconds(MIDITimeStamp timestamp) { + UInt64 nanoseconds = AudioConvertHostTimeToNanos(timestamp); + return static_cast<double>(nanoseconds) / 1.0e9; +} + +MIDITimeStamp MIDIManagerMac::SecondsToMIDITimeStamp(double seconds) { + UInt64 nanos = UInt64(seconds * 1.0e9); + return AudioConvertNanosToHostTime(nanos); +} + +} // namespace media diff --git a/media/midi/midi_manager_mac.h b/media/midi/midi_manager_mac.h new file mode 100644 index 0000000..f513e11 --- /dev/null +++ b/media/midi/midi_manager_mac.h @@ -0,0 +1,69 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_MIDI_MIDI_MANAGER_MAC_H_ +#define MEDIA_MIDI_MIDI_MANAGER_MAC_H_ + +#include <CoreMIDI/MIDIServices.h> +#include <map> +#include <string> + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "media/midi/midi_manager.h" +#include "media/midi/midi_port_info.h" + +namespace media { + +class MEDIA_EXPORT MIDIManagerMac : public MIDIManager { + public: + MIDIManagerMac(); + virtual ~MIDIManagerMac(); + + // MIDIManager implementation. + virtual bool Initialize() OVERRIDE; + virtual void SendMIDIData(int port_index, + const uint8* data, + size_t length, + double timestamp) OVERRIDE; + + private: + // CoreMIDI callback for MIDI data. + // Each callback can contain multiple packets, each of which can contain + // multiple MIDI messages. + static void ReadMidiDispatch( + const MIDIPacketList *pktlist, + void *read_proc_refcon, + void *src_conn_refcon); + virtual void ReadMidi(MIDIEndpointRef source, const MIDIPacketList *pktlist); + + // Helper + static media::MIDIPortInfo GetPortInfoFromEndpoint(MIDIEndpointRef endpoint); + static double MIDITimeStampToSeconds(MIDITimeStamp timestamp); + static MIDITimeStamp SecondsToMIDITimeStamp(double seconds); + + // CoreMIDI + MIDIClientRef midi_client_; + MIDIPortRef coremidi_input_; + MIDIPortRef coremidi_output_; + + enum{ kMaxPacketListSize = 512 }; + char midi_buffer_[kMaxPacketListSize]; + MIDIPacketList* packet_list_; + MIDIPacket* midi_packet_; + + typedef std::map<MIDIEndpointRef, int> SourceMap; + + // Keeps track of the index (0-based) for each of our sources. + SourceMap source_map_; + + // Keeps track of all destinations. + std::vector<MIDIEndpointRef> destinations_; + + DISALLOW_COPY_AND_ASSIGN(MIDIManagerMac); +}; + +} // namespace media + +#endif // MEDIA_MIDI_MIDI_MANAGER_MAC_H_ diff --git a/media/midi/midi_port_info.cc b/media/midi/midi_port_info.cc new file mode 100644 index 0000000..3be7007 --- /dev/null +++ b/media/midi/midi_port_info.cc @@ -0,0 +1,28 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "media/midi/midi_port_info.h" + +namespace media { + +MIDIPortInfo::MIDIPortInfo() {} + +MIDIPortInfo::MIDIPortInfo(const std::string& in_id, + const std::string& in_manufacturer, + const std::string& in_name, + const std::string& in_version) + : id(in_id), + manufacturer(in_manufacturer), + name(in_name), + version(in_version) {} + +MIDIPortInfo::~MIDIPortInfo() {} + +MIDIPortInfo::MIDIPortInfo(const MIDIPortInfo& info) + : id(info.id), + manufacturer(info.manufacturer), + name(info.name), + version(info.version) {} + +} // namespace media diff --git a/media/midi/midi_port_info.h b/media/midi/midi_port_info.h new file mode 100644 index 0000000..f4afb49 --- /dev/null +++ b/media/midi/midi_port_info.h @@ -0,0 +1,36 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_MIDI_MIDI_PORT_INFO_H_ +#define MEDIA_MIDI_MIDI_PORT_INFO_H_ + +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "media/base/media_export.h" + +namespace media { + +struct MEDIA_EXPORT MIDIPortInfo { + MIDIPortInfo(); + MIDIPortInfo(const std::string& in_id, + const std::string& in_manufacturer, + const std::string& in_name, + const std::string& in_version); + + MIDIPortInfo(const MIDIPortInfo& info); + ~MIDIPortInfo(); + + std::string id; + std::string manufacturer; + std::string name; + std::string version; +}; + +typedef std::vector<MIDIPortInfo> MIDIPortInfoList; + +} // namespace media + +#endif // MEDIA_MIDI_MIDI_PORT_INFO_H_ |