Compare commits
6 Commits
master
...
ActiveSens
| Author | SHA1 | Date |
|---|---|---|
|
|
37ef1d48d9 | |
|
|
ca3371a7f2 | |
|
|
1640504544 | |
|
|
e83ea63979 | |
|
|
5972ae5e24 | |
|
|
2685bb458b |
|
|
@ -1,66 +0,0 @@
|
|||
---
|
||||
name: Bug report
|
||||
about: Report something that does not work as intended
|
||||
title: ''
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!--
|
||||
Before opening an issue, check if your problem already has been solved by looking in:
|
||||
- The existing issues: https://github.com/FortySevenEffects/arduino_midi_library/issues
|
||||
- The discussions: https://github.com/FortySevenEffects/arduino_midi_library/discussions
|
||||
|
||||
Consider opening a discussion instead of an issue if you need help with your project:
|
||||
https://github.com/FortySevenEffects/arduino_midi_library/discussions/new
|
||||
-->
|
||||
|
||||
## Context
|
||||
|
||||
Please answer a few questions to help us understand your problem better and guide you to a solution:
|
||||
|
||||
<!-- Tip: place the letter x in the checkboxes to tick them:
|
||||
- [ ] Unticked checkbox
|
||||
- [x] Ticked checkbox
|
||||
|
||||
You can also tick them by clicking after you've submitted your issue.
|
||||
-->
|
||||
|
||||
- What board are you using ?
|
||||
- `example: Arduino Leonardo`
|
||||
- _Please list any shields or other **relevant** hardware you're using_
|
||||
- What version of the Arduino IDE are you using ?
|
||||
- `example: 1.8.5`
|
||||
- How are you using MIDI ?
|
||||
- [ ] Hardware Serial (DIN plugs)
|
||||
- [ ] USB
|
||||
- [ ] Other (please specify)
|
||||
- Is your problem related to:
|
||||
- [ ] MIDI Input (reading messages from other devices)
|
||||
- [ ] MIDI Output (sending messages to other devices)
|
||||
- How comfortable are you with code ?
|
||||
- [ ] Complete beginner
|
||||
- [ ] I've done basic projects
|
||||
- [ ] I know my way around C/C++
|
||||
- [ ] Advanced / professional
|
||||
|
||||
## Describe your project and what you expect to happen:
|
||||
|
||||
<!--
|
||||
Example: When I press a switch on my pedalboard, it sends a SysEx message that I'd like to receive on my Arduino.
|
||||
|
||||
Note: Attachments (circuit diagrams, code examples) are most welcome and will help us understand your needs better and find a suitable solution for your issue.
|
||||
-->
|
||||
|
||||
## Describe your problem (what does not work):
|
||||
|
||||
<!--
|
||||
Example: I cannot receive SysEx messages coming from my AxeFX 2
|
||||
-->
|
||||
|
||||
## Steps to reproduce
|
||||
|
||||
<!--
|
||||
Please list the steps you took to hit the problem, so we can try and reproduce it.
|
||||
-->
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Discussions
|
||||
url: https://github.com/FortySevenEffects/arduino_midi_library/discussions
|
||||
about: Not a bug or a feature request ? Discuss your problem, ask for help or show what you've built in Discussions.
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: new feature
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
name: CMake
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
env:
|
||||
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
|
||||
BUILD_TYPE: Debug
|
||||
GENERATE_COVERAGE: true
|
||||
LCOV_ROOT: ${{github.workspace}}/lcov
|
||||
|
||||
jobs:
|
||||
build:
|
||||
# The CMake configure and build commands are platform agnostic and should work equally
|
||||
# well on Windows or Mac. You can convert this to a matrix build if you need
|
||||
# cross-platform coverage.
|
||||
# See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Install lcov
|
||||
run: |
|
||||
mkdir -p "$LCOV_ROOT"
|
||||
wget https://github.com/linux-test-project/lcov/releases/download/v1.15/lcov-1.15.tar.gz --output-document="$LCOV_ROOT/lcov.tar.gz"
|
||||
tar -xf "$LCOV_ROOT/lcov.tar.gz" --strip-components=1 -C "$LCOV_ROOT"
|
||||
echo "$LCOV_ROOT/bin" >> $GITHUB_PATH
|
||||
shell: bash
|
||||
|
||||
- name: Configure CMake
|
||||
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
|
||||
# See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
|
||||
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DBUILDER_ENABLE_PROFILING=true
|
||||
|
||||
- name: Build
|
||||
# Build your program with the given configuration
|
||||
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
|
||||
|
||||
- name: Run Unit Tests
|
||||
working-directory: ${{github.workspace}}/build
|
||||
run: ctest --verbose
|
||||
|
||||
- name: Generate code coverage report
|
||||
working-directory: ${{github.workspace}}/build
|
||||
run: |
|
||||
lcov --directory . --capture --output-file coverage.info
|
||||
lcov --remove coverage.info '/usr/*' "${{github.workspace}}/test/*" "${{github.workspace}}/external/*" --output-file coverage.info
|
||||
lcov --list coverage.info
|
||||
|
||||
- uses: coverallsapp/github-action@9ba913c152ae4be1327bfb9085dc806cedb44057
|
||||
name: Upload code coverage report to Coveralls
|
||||
with:
|
||||
path-to-lcov: ${{github.workspace}}/build/coverage.info
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
name: PlatformIO
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
platformio:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
example:
|
||||
- AltPinSerial
|
||||
- Basic_IO
|
||||
- Bench
|
||||
- Callbacks
|
||||
- Chaining
|
||||
- DualMerger
|
||||
- ErrorCallback
|
||||
- Input
|
||||
- RPN_NRPN
|
||||
- SimpleSynth
|
||||
- CustomBaudRate
|
||||
board:
|
||||
- uno
|
||||
- due
|
||||
- zero
|
||||
- leonardo
|
||||
- micro
|
||||
- nanoatmega328
|
||||
- megaatmega2560
|
||||
- teensy2
|
||||
- teensy30
|
||||
- teensy31
|
||||
- teensylc
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Cache pip
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
||||
restore-keys: ${{ runner.os }}-pip-
|
||||
- name: Cache PlatformIO
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.platformio
|
||||
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v2
|
||||
- name: Install PlatformIO
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install --upgrade platformio
|
||||
pip install "click!=8.0.2" # See platformio/platformio-core#4078
|
||||
- name: Run PlatformIO
|
||||
run: pio ci --lib="." --board="${{matrix.board}}"
|
||||
env:
|
||||
PLATFORMIO_CI_SRC: examples/${{ matrix.example }}
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
# Kudos to these guys:
|
||||
# https://github.com/Return-To-The-Roots/s25client/blob/master/.travis.yml
|
||||
# http://docs.platformio.org/en/stable/ci/travis.html
|
||||
|
||||
sudo: false
|
||||
language: python
|
||||
|
||||
os:
|
||||
- linux
|
||||
|
||||
python:
|
||||
- "2.7"
|
||||
|
||||
# Cache PlatformIO packages using Travis CI container-based infrastructure
|
||||
cache:
|
||||
directories:
|
||||
- "~/.platformio"
|
||||
|
||||
env:
|
||||
global:
|
||||
- BUILD_TYPE=Debug
|
||||
matrix:
|
||||
- BUILD_UNIT_TESTS=1
|
||||
- PLATFORMIO_CI_SRC=examples/Basic_IO
|
||||
- PLATFORMIO_CI_SRC=examples/Bench
|
||||
- PLATFORMIO_CI_SRC=examples/Callbacks
|
||||
- PLATFORMIO_CI_SRC=examples/DualMerger
|
||||
- PLATFORMIO_CI_SRC=examples/ErrorCallback
|
||||
- PLATFORMIO_CI_SRC=examples/Input
|
||||
- PLATFORMIO_CI_SRC=examples/RPN_NRPN
|
||||
- PLATFORMIO_CI_SRC=examples/SimpleSynth
|
||||
- PLATFORMIO_CI_SRC=examples/AltPinSerial
|
||||
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-4.8
|
||||
- cmake
|
||||
|
||||
install:
|
||||
- |
|
||||
if [ "${BUILD_UNIT_TESTS}" ]; then
|
||||
# GCov 4.6 cannot handle the file structure
|
||||
export CXX="g++-4.8"
|
||||
export GCOV="gcov-4.8"
|
||||
|
||||
# Install newer lcov (1.9 seems to fail: http://gronlier.fr/blog/2015/01/adding-code-coverage-to-your-c-project/)
|
||||
export LCOV_ROOT="$HOME/lcov"
|
||||
mkdir -p "$LCOV_ROOT"
|
||||
wget http://ftp.de.debian.org/debian/pool/main/l/lcov/lcov_1.14.orig.tar.gz --output-document="$LCOV_ROOT/lcov.tar.gz"
|
||||
tar xf "$LCOV_ROOT/lcov.tar.gz" --strip-components=1 -C $LCOV_ROOT
|
||||
export PATH="$LCOV_ROOT/bin:$PATH"
|
||||
which lcov
|
||||
|
||||
# Install coveralls tool
|
||||
gem install coveralls-lcov
|
||||
export GENERATE_COVERAGE=1
|
||||
else
|
||||
# Install PlatformIO
|
||||
pip install -U platformio
|
||||
fi
|
||||
|
||||
script:
|
||||
# Build unit tests & generate code coverage
|
||||
- |
|
||||
if [ "${BUILD_UNIT_TESTS}" ]; then
|
||||
mkdir build && cd build
|
||||
cmake -DCMAKE_CXX_COMPILER=$COMPILER -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DBUILDER_ENABLE_PROFILING=${GENERATE_COVERAGE} --generator="Unix Makefiles" ..
|
||||
make all
|
||||
ctest --verbose
|
||||
fi
|
||||
|
||||
# Build current example
|
||||
- |
|
||||
if [ ! "${BUILD_UNIT_TESTS}" ]; then
|
||||
platformio ci --lib="." \
|
||||
--board="uno" \
|
||||
--board="due" \
|
||||
--board="zero" \
|
||||
--board="leonardo" \
|
||||
--board="micro" \
|
||||
--board="nanoatmega328" \
|
||||
--board="megaatmega2560" \
|
||||
--board="teensy2" \
|
||||
--board="teensy30" \
|
||||
--board="teensy31" \
|
||||
--board="teensylc"
|
||||
fi
|
||||
|
||||
after_success:
|
||||
- |
|
||||
if [ "${GENERATE_COVERAGE}" ]; then
|
||||
# Generate code coverage information & send to Coveralls
|
||||
rm -rf ./external/google-test/googletest/CMakeFiles/gtest.dir/src/gtest-all.cc.gcda
|
||||
lcov --gcov-tool $GCOV --directory . --capture --output-file coverage.info
|
||||
lcov --gcov-tool $GCOV --remove coverage.info 'test/*' '/usr/*' 'external/*' --output-file coverage.info
|
||||
lcov --list coverage.info
|
||||
coveralls-lcov --repo-token ${COVERALLS_TOKEN} coverage.info
|
||||
fi
|
||||
|
||||
notifications:
|
||||
email: false
|
||||
|
|
@ -8,7 +8,6 @@
|
|||
"string": "cpp",
|
||||
"string_view": "cpp",
|
||||
"vector": "cpp",
|
||||
"istream": "cpp",
|
||||
"system_error": "cpp"
|
||||
"istream": "cpp"
|
||||
}
|
||||
}
|
||||
14
README.md
14
README.md
|
|
@ -1,10 +1,9 @@
|
|||
# Arduino MIDI Library
|
||||
|
||||
[](https://travis-ci.org/FortySevenEffects/arduino_midi_library)
|
||||
[](https://coveralls.io/github/FortySevenEffects/arduino_midi_library)
|
||||
[](https://github.com/FortySevenEffects/arduino_midi_library/releases/latest)
|
||||
[](LICENSE)
|
||||
[](https://github.com/FortySevenEffects/arduino_midi_library/actions/workflows/cmake.yml)
|
||||
[](https://github.com/FortySevenEffects/arduino_midi_library/actions/workflows/platformio.yml)
|
||||
[](https://coveralls.io/github/FortySevenEffects/arduino_midi_library)
|
||||
|
||||
This library adds MIDI I/O communications to an Arduino board.
|
||||
|
||||
|
|
@ -25,7 +24,7 @@ This library adds MIDI I/O communications to an Arduino board.
|
|||
### Getting Started
|
||||
|
||||
1. Use the Arduino Library Manager to install the library.
|
||||

|
||||

|
||||
|
||||
2. Start coding:
|
||||
|
||||
|
|
@ -112,9 +111,9 @@ protocol bridges.
|
|||
|
||||
- Software Thru is enabled by default on Serial, but not on other transports.
|
||||
|
||||
## Contact & Contribution
|
||||
## Contact
|
||||
|
||||
To report a bug, contribute, discuss on usage, or request support, please [discuss it here](https://github.com/FortySevenEffects/arduino_midi_library/discussions/new).
|
||||
To report a bug, contribute, discuss on usage, or simply request support, please [create an issue here](https://github.com/FortySevenEffects/arduino_midi_library/issues/new).
|
||||
|
||||
You can also contact me on Twitter: [@fortysevenfx](https://twitter.com/fortysevenfx).
|
||||
|
||||
|
|
@ -131,9 +130,6 @@ Special thanks to all who have contributed to this open-source project !
|
|||
- [@LnnrtS](https://github.com/LnnrtS)
|
||||
- [@DavidMenting](https://github.com/DavidMenting)
|
||||
- [@Rolel](https://github.com/Rolel)
|
||||
- [@kant](https://github.com/kant)
|
||||
- [@paul-emile-element](https://github.com/paul-emile-element)
|
||||
- [@muxa](https://github.com/muxa)
|
||||
|
||||
You want to help ? Check out the [contribution guidelines](./CONTRIBUTING.md).
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
// Examples
|
||||
|
||||
/*!
|
||||
\example Basic_IO.ino
|
||||
\example MIDI_Basic_IO.ino
|
||||
This example shows how to perform simple input and output MIDI. \n
|
||||
\n
|
||||
When any message arrives to the Arduino, the LED is turned on,
|
||||
|
|
@ -29,15 +29,15 @@
|
|||
*/
|
||||
|
||||
/*!
|
||||
\example Callbacks.ino
|
||||
\example MIDI_Callbacks.ino
|
||||
This example shows how to use callbacks for easier MIDI input handling. \n
|
||||
*/
|
||||
|
||||
/*!
|
||||
\example Bench.ino
|
||||
\example DualMerger.ino
|
||||
\example Input.ino
|
||||
\example SimpleSynth.ino
|
||||
\example MIDI_Bench.ino
|
||||
\example MIDI_DualMerger.ino
|
||||
\example MIDI_Input.ino
|
||||
\example MIDI_SimpleSynth.ino
|
||||
*/
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ becomes:
|
|||
```
|
||||
|
||||
The order of the bits in the "header" byte is reversed.
|
||||
To follow this behaviour, set the inFlipHeaderBits argument to true.
|
||||
To follow this beheaviour, set the inFlipHeaderBits argument to true.
|
||||
|
||||
Example:
|
||||
```c++
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
// Here, when receiving any message on channel 4, the Arduino
|
||||
// will blink a led and play back a note for 1 second.
|
||||
|
||||
#if defined(ARDUINO_SAM_DUE) || defined(SAMD_SERIES) || defined(_VARIANT_ARDUINO_ZERO_)
|
||||
#if defined(ARDUINO_SAM_DUE) || defined(SAMD_SERIES)
|
||||
/* example not relevant for this hardware (SoftwareSerial not supported) */
|
||||
MIDI_CREATE_DEFAULT_INSTANCE();
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -1,37 +0,0 @@
|
|||
#include <MIDI.h>
|
||||
|
||||
MIDI_CREATE_DEFAULT_INSTANCE();
|
||||
|
||||
void setup()
|
||||
{
|
||||
pinMode(2, INPUT);
|
||||
|
||||
MIDI // chaining MIDI commands - order is from top to bottom (turnThruOff,... begin)
|
||||
.turnThruOff()
|
||||
// using a lamdba function for this callbacks
|
||||
.setHandleNoteOn([](byte channel, byte note, byte velocity)
|
||||
{
|
||||
// Do whatever you want when a note is pressed.
|
||||
|
||||
// Try to keep your callbacks short (no delays ect)
|
||||
// otherwise it would slow down the loop() and have a bad impact
|
||||
// on real-time performance.
|
||||
})
|
||||
.setHandleNoteOff([](byte channel, byte note, byte velocity)
|
||||
{
|
||||
// Do something when the note is released.
|
||||
// Note that NoteOn messages with 0 velocity are interpreted as NoteOffs.
|
||||
})
|
||||
.begin(MIDI_CHANNEL_OMNI); // Initiate MIDI communications, listen to all channels
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// Call MIDI.read the fastest you can for real-time performance.
|
||||
MIDI.read();
|
||||
|
||||
if (digitalRead(2))
|
||||
MIDI // chained sendNoteOn commands
|
||||
.sendNoteOn(42, 127, 1)
|
||||
.sendNoteOn(40, 54, 1);
|
||||
}
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
#include <MIDI.h>
|
||||
|
||||
// Override the default MIDI baudrate to
|
||||
// a decoding program such as Hairless MIDI (set baudrate to 115200)
|
||||
struct CustomBaudRateSettings : public MIDI_NAMESPACE::DefaultSerialSettings {
|
||||
static const long BaudRate = 115200;
|
||||
};
|
||||
|
||||
#if defined(ARDUINO_SAM_DUE) || defined(USBCON) || defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MKL26Z64__)
|
||||
// Leonardo, Due and other USB boards use Serial1 by default.
|
||||
MIDI_NAMESPACE::SerialMIDI<HardwareSerial, CustomBaudRateSettings> serialMIDI(Serial1);
|
||||
MIDI_NAMESPACE::MidiInterface<MIDI_NAMESPACE::SerialMIDI<HardwareSerial, CustomBaudRateSettings>> MIDI((MIDI_NAMESPACE::SerialMIDI<HardwareSerial, CustomBaudRateSettings>&)serialMIDI);
|
||||
#else
|
||||
MIDI_NAMESPACE::SerialMIDI<HardwareSerial, CustomBaudRateSettings> serialMIDI(Serial);
|
||||
MIDI_NAMESPACE::MidiInterface<MIDI_NAMESPACE::SerialMIDI<HardwareSerial, CustomBaudRateSettings>> MIDI((MIDI_NAMESPACE::SerialMIDI<HardwareSerial, CustomBaudRateSettings>&)serialMIDI);
|
||||
#endif
|
||||
|
||||
void setup() {
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
MIDI.begin(MIDI_CHANNEL_OMNI);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
if (MIDI.read()) // If we have received a message
|
||||
{
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
MIDI.sendNoteOn(42, 127, 1); // Send a Note (pitch 42, velo 127 on channel 1)
|
||||
delay(1000); // Wait for a second
|
||||
MIDI.sendNoteOff(42, 0, 1); // Stop the note
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
#include <MIDI.h>
|
||||
USING_NAMESPACE_MIDI
|
||||
|
||||
struct MySerialSettings : public MIDI_NAMESPACE::DefaultSerialSettings
|
||||
{
|
||||
static const long BaudRate = 115200;
|
||||
};
|
||||
|
||||
unsigned long t1 = millis();
|
||||
|
||||
MIDI_NAMESPACE::SerialMIDI<HardwareSerial, MySerialSettings> serialMIDI(Serial1);
|
||||
MIDI_NAMESPACE::MidiInterface<MIDI_NAMESPACE::SerialMIDI<HardwareSerial, MySerialSettings>> MIDI((MIDI_NAMESPACE::SerialMIDI<HardwareSerial, MySerialSettings>&)serialMIDI);
|
||||
|
||||
void setup()
|
||||
{
|
||||
MIDI.begin(1);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
MIDI.read();
|
||||
|
||||
// send a note every second
|
||||
if ((millis() - t1) > 1000)
|
||||
{
|
||||
t1 = millis();
|
||||
|
||||
MIDI.sendNoteOn(random(1, 127), 55, 1);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
#include <MIDI.h>
|
||||
USING_NAMESPACE_MIDI
|
||||
|
||||
struct MyMIDISettings : public MIDI_NAMESPACE::DefaultSettings
|
||||
{
|
||||
// When setting UseReceiverActiveSensing to true, MIDI.read() *must* be called
|
||||
// as often as possible (1000 / SenderActiveSensingPeriodicity per second).
|
||||
//
|
||||
// setting UseReceiverActiveSensing to true, adds 174 bytes of code.
|
||||
//
|
||||
// (Taken from a Roland MIDI Implementation Owner's manual)
|
||||
// Once an Active Sensing message is received, the unit will begin monitoring
|
||||
// the interval between all subsequent messages. If there is an interval of 420 ms
|
||||
// or longer between messages while monitoring is active, the same processing
|
||||
// as when All Sound Off, All Notes Off,and Reset All Controllers messages are
|
||||
// received will be carried out. The unit will then stopmonitoring the message interval.
|
||||
|
||||
static const bool UseReceiverActiveSensing = true;
|
||||
|
||||
static const uint16_t ReceiverActiveSensingTimeout = 420;
|
||||
};
|
||||
|
||||
MIDI_CREATE_CUSTOM_INSTANCE(HardwareSerial, Serial1, MIDI, MyMIDISettings);
|
||||
|
||||
void activeSensingTimeoutExceptionHandler(bool active)
|
||||
{
|
||||
if (!active)
|
||||
{
|
||||
MIDI.sendControlChange(AllSoundOff, 0, 1);
|
||||
MIDI.sendControlChange(AllNotesOff, 0, 1);
|
||||
MIDI.sendControlChange(ResetAllControllers, 0, 1);
|
||||
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
}
|
||||
else
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
|
||||
MIDI.setHandleActiveSensingTimeout(activeSensingTimeoutExceptionHandler);
|
||||
MIDI.begin(1);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
MIDI.read();
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
#include <MIDI.h>
|
||||
USING_NAMESPACE_MIDI
|
||||
|
||||
struct MyMIDISettings : public MIDI_NAMESPACE::DefaultSettings
|
||||
{
|
||||
// When setting UseSenderActiveSensing to true, MIDI.read() *must* be called
|
||||
// as often as possible (1000 / SenderActiveSensingPeriodicity per second).
|
||||
//
|
||||
// setting UseSenderActiveSensing to true, adds 34 bytes of code.
|
||||
//
|
||||
// When using Active Sensing, call MIDI.read(); in the Arduino loop()
|
||||
//
|
||||
// from 'a' MIDI implementation manual: "Sent periodically"
|
||||
// In the example here, a NoteOn is send every 1000ms (1s), ActiveSensing is
|
||||
// send every 250ms after the last command.
|
||||
// Logging the command will look like this:
|
||||
//
|
||||
// ...
|
||||
// A.Sense FE
|
||||
// A.Sense FE
|
||||
// A.Sense FE
|
||||
// NoteOn 90 04 37 [E-2]
|
||||
// A.Sense FE
|
||||
// A.Sense FE
|
||||
// A.Sense FE
|
||||
// NoteOn 90 04 37 [E-2]
|
||||
// A.Sense FE
|
||||
// A.Sense FE
|
||||
// A.Sense FE
|
||||
// NoteOn 90 04 37 [E-2]
|
||||
// ...
|
||||
|
||||
static const bool UseSenderActiveSensing = true;
|
||||
|
||||
static const uint16_t SenderActiveSensingPeriodicity = 250;
|
||||
};
|
||||
|
||||
unsigned long t1 = millis();
|
||||
|
||||
MIDI_CREATE_CUSTOM_INSTANCE(HardwareSerial, Serial1, MIDI, MyMIDISettings);
|
||||
|
||||
void setup()
|
||||
{
|
||||
MIDI.begin(1);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
MIDI.read();
|
||||
|
||||
// send a note every second
|
||||
if ((millis() - t1) > 1000)
|
||||
{
|
||||
t1 = millis();
|
||||
|
||||
MIDI.sendNoteOn(random(1, 127), 55, 1);
|
||||
}
|
||||
}
|
||||
11
keywords.txt
11
keywords.txt
|
|
@ -146,18 +146,7 @@ GeneralPurposeController1 LITERAL1
|
|||
GeneralPurposeController2 LITERAL1
|
||||
GeneralPurposeController3 LITERAL1
|
||||
GeneralPurposeController4 LITERAL1
|
||||
BankSelectLSB LITERAL1
|
||||
ModulationWheelLSB LITERAL1
|
||||
BreathControllerLSB LITERAL1
|
||||
FootControllerLSB LITERAL1
|
||||
PortamentoTimeLSB LITERAL1
|
||||
DataEntryLSB LITERAL1
|
||||
ChannelVolumeLSB LITERAL1
|
||||
BalanceLSB LITERAL1
|
||||
PanLSB LITERAL1
|
||||
ExpressionControllerLSB LITERAL1
|
||||
EffectControl1LSB LITERAL1
|
||||
EffectControl2LSB LITERAL1
|
||||
Sustain LITERAL1
|
||||
Portamento LITERAL1
|
||||
Sostenuto LITERAL1
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 72 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 18 KiB |
137
src/MIDI.h
137
src/MIDI.h
|
|
@ -62,94 +62,94 @@ public:
|
|||
inline ~MidiInterface();
|
||||
|
||||
public:
|
||||
MidiInterface& begin(Channel inChannel = 1);
|
||||
void begin(Channel inChannel = 1);
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// MIDI Output
|
||||
|
||||
public:
|
||||
inline MidiInterface& sendNoteOn(DataByte inNoteNumber,
|
||||
inline void sendNoteOn(DataByte inNoteNumber,
|
||||
DataByte inVelocity,
|
||||
Channel inChannel);
|
||||
|
||||
inline MidiInterface& sendNoteOff(DataByte inNoteNumber,
|
||||
inline void sendNoteOff(DataByte inNoteNumber,
|
||||
DataByte inVelocity,
|
||||
Channel inChannel);
|
||||
|
||||
inline MidiInterface& sendProgramChange(DataByte inProgramNumber,
|
||||
inline void sendProgramChange(DataByte inProgramNumber,
|
||||
Channel inChannel);
|
||||
|
||||
inline MidiInterface& sendControlChange(DataByte inControlNumber,
|
||||
inline void sendControlChange(DataByte inControlNumber,
|
||||
DataByte inControlValue,
|
||||
Channel inChannel);
|
||||
|
||||
inline MidiInterface& sendPitchBend(int inPitchValue, Channel inChannel);
|
||||
inline MidiInterface& sendPitchBend(double inPitchValue, Channel inChannel);
|
||||
inline void sendPitchBend(int inPitchValue, Channel inChannel);
|
||||
inline void sendPitchBend(double inPitchValue, Channel inChannel);
|
||||
|
||||
inline MidiInterface& sendPolyPressure(DataByte inNoteNumber,
|
||||
inline void sendPolyPressure(DataByte inNoteNumber,
|
||||
DataByte inPressure,
|
||||
Channel inChannel) __attribute__ ((deprecated));
|
||||
|
||||
inline MidiInterface& sendAfterTouch(DataByte inPressure,
|
||||
inline void sendAfterTouch(DataByte inPressure,
|
||||
Channel inChannel);
|
||||
inline MidiInterface& sendAfterTouch(DataByte inNoteNumber,
|
||||
inline void sendAfterTouch(DataByte inNoteNumber,
|
||||
DataByte inPressure,
|
||||
Channel inChannel);
|
||||
|
||||
inline MidiInterface& sendSysEx(unsigned inLength,
|
||||
inline void sendSysEx(unsigned inLength,
|
||||
const byte* inArray,
|
||||
bool inArrayContainsBoundaries = false);
|
||||
|
||||
inline MidiInterface& sendTimeCodeQuarterFrame(DataByte inTypeNibble,
|
||||
inline void sendTimeCodeQuarterFrame(DataByte inTypeNibble,
|
||||
DataByte inValuesNibble);
|
||||
inline MidiInterface& sendTimeCodeQuarterFrame(DataByte inData);
|
||||
inline void sendTimeCodeQuarterFrame(DataByte inData);
|
||||
|
||||
inline MidiInterface& sendSongPosition(unsigned inBeats);
|
||||
inline MidiInterface& sendSongSelect(DataByte inSongNumber);
|
||||
inline MidiInterface& sendTuneRequest();
|
||||
inline void sendSongPosition(unsigned inBeats);
|
||||
inline void sendSongSelect(DataByte inSongNumber);
|
||||
inline void sendTuneRequest();
|
||||
|
||||
inline MidiInterface& sendCommon(MidiType inType, unsigned = 0);
|
||||
inline void sendCommon(MidiType inType, unsigned = 0);
|
||||
|
||||
inline MidiInterface& sendClock() { return sendRealTime(Clock); };
|
||||
inline MidiInterface& sendStart() { return sendRealTime(Start); };
|
||||
inline MidiInterface& sendStop() { return sendRealTime(Stop); };
|
||||
inline MidiInterface& sendTick() { return sendRealTime(Tick); };
|
||||
inline MidiInterface& sendContinue() { return sendRealTime(Continue); };
|
||||
inline MidiInterface& sendActiveSensing() { return sendRealTime(ActiveSensing); };
|
||||
inline MidiInterface& sendSystemReset() { return sendRealTime(SystemReset); };
|
||||
inline void sendClock() { sendRealTime(Clock); };
|
||||
inline void sendStart() { sendRealTime(Start); };
|
||||
inline void sendStop() { sendRealTime(Stop); };
|
||||
inline void sendTick() { sendRealTime(Tick); };
|
||||
inline void sendContinue() { sendRealTime(Continue); };
|
||||
inline void sendActiveSensing() { sendRealTime(ActiveSensing); };
|
||||
inline void sendSystemReset() { sendRealTime(SystemReset); };
|
||||
|
||||
inline MidiInterface& sendRealTime(MidiType inType);
|
||||
inline void sendRealTime(MidiType inType);
|
||||
|
||||
inline MidiInterface& beginRpn(unsigned inNumber,
|
||||
inline void beginRpn(unsigned inNumber,
|
||||
Channel inChannel);
|
||||
inline MidiInterface& sendRpnValue(unsigned inValue,
|
||||
inline void sendRpnValue(unsigned inValue,
|
||||
Channel inChannel);
|
||||
inline MidiInterface& sendRpnValue(byte inMsb,
|
||||
inline void sendRpnValue(byte inMsb,
|
||||
byte inLsb,
|
||||
Channel inChannel);
|
||||
inline MidiInterface& sendRpnIncrement(byte inAmount,
|
||||
inline void sendRpnIncrement(byte inAmount,
|
||||
Channel inChannel);
|
||||
inline MidiInterface& sendRpnDecrement(byte inAmount,
|
||||
inline void sendRpnDecrement(byte inAmount,
|
||||
Channel inChannel);
|
||||
inline MidiInterface& endRpn(Channel inChannel);
|
||||
inline void endRpn(Channel inChannel);
|
||||
|
||||
inline MidiInterface& beginNrpn(unsigned inNumber,
|
||||
inline void beginNrpn(unsigned inNumber,
|
||||
Channel inChannel);
|
||||
inline MidiInterface& sendNrpnValue(unsigned inValue,
|
||||
inline void sendNrpnValue(unsigned inValue,
|
||||
Channel inChannel);
|
||||
inline MidiInterface& sendNrpnValue(byte inMsb,
|
||||
inline void sendNrpnValue(byte inMsb,
|
||||
byte inLsb,
|
||||
Channel inChannel);
|
||||
inline MidiInterface& sendNrpnIncrement(byte inAmount,
|
||||
inline void sendNrpnIncrement(byte inAmount,
|
||||
Channel inChannel);
|
||||
inline MidiInterface& sendNrpnDecrement(byte inAmount,
|
||||
inline void sendNrpnDecrement(byte inAmount,
|
||||
Channel inChannel);
|
||||
inline MidiInterface& endNrpn(Channel inChannel);
|
||||
inline void endNrpn(Channel inChannel);
|
||||
|
||||
inline MidiInterface& send(const MidiMessage&);
|
||||
inline void send(const MidiMessage&);
|
||||
|
||||
public:
|
||||
MidiInterface& send(MidiType inType,
|
||||
void send(MidiType inType,
|
||||
DataByte inData1,
|
||||
DataByte inData2,
|
||||
Channel inChannel);
|
||||
|
|
@ -172,7 +172,7 @@ public:
|
|||
|
||||
public:
|
||||
inline Channel getInputChannel() const;
|
||||
inline MidiInterface& setInputChannel(Channel inChannel);
|
||||
inline void setInputChannel(Channel inChannel);
|
||||
|
||||
public:
|
||||
static inline MidiType getTypeFromStatusByte(byte inStatus);
|
||||
|
|
@ -183,35 +183,37 @@ public:
|
|||
// Input Callbacks
|
||||
|
||||
public:
|
||||
inline MidiInterface& setHandleMessage(void (*fptr)(const MidiMessage&)) { mMessageCallback = fptr; return *this; };
|
||||
inline MidiInterface& setHandleError(ErrorCallback fptr) { mErrorCallback = fptr; return *this; };
|
||||
inline MidiInterface& setHandleNoteOff(NoteOffCallback fptr) { mNoteOffCallback = fptr; return *this; };
|
||||
inline MidiInterface& setHandleNoteOn(NoteOnCallback fptr) { mNoteOnCallback = fptr; return *this; };
|
||||
inline MidiInterface& setHandleAfterTouchPoly(AfterTouchPolyCallback fptr) { mAfterTouchPolyCallback = fptr; return *this; };
|
||||
inline MidiInterface& setHandleControlChange(ControlChangeCallback fptr) { mControlChangeCallback = fptr; return *this; };
|
||||
inline MidiInterface& setHandleProgramChange(ProgramChangeCallback fptr) { mProgramChangeCallback = fptr; return *this; };
|
||||
inline MidiInterface& setHandleAfterTouchChannel(AfterTouchChannelCallback fptr) { mAfterTouchChannelCallback = fptr; return *this; };
|
||||
inline MidiInterface& setHandlePitchBend(PitchBendCallback fptr) { mPitchBendCallback = fptr; return *this; };
|
||||
inline MidiInterface& setHandleSystemExclusive(SystemExclusiveCallback fptr) { mSystemExclusiveCallback = fptr; return *this; };
|
||||
inline MidiInterface& setHandleTimeCodeQuarterFrame(TimeCodeQuarterFrameCallback fptr) { mTimeCodeQuarterFrameCallback = fptr; return *this; };
|
||||
inline MidiInterface& setHandleSongPosition(SongPositionCallback fptr) { mSongPositionCallback = fptr; return *this; };
|
||||
inline MidiInterface& setHandleSongSelect(SongSelectCallback fptr) { mSongSelectCallback = fptr; return *this; };
|
||||
inline MidiInterface& setHandleTuneRequest(TuneRequestCallback fptr) { mTuneRequestCallback = fptr; return *this; };
|
||||
inline MidiInterface& setHandleClock(ClockCallback fptr) { mClockCallback = fptr; return *this; };
|
||||
inline MidiInterface& setHandleStart(StartCallback fptr) { mStartCallback = fptr; return *this; };
|
||||
inline MidiInterface& setHandleTick(TickCallback fptr) { mTickCallback = fptr; return *this; };
|
||||
inline MidiInterface& setHandleContinue(ContinueCallback fptr) { mContinueCallback = fptr; return *this; };
|
||||
inline MidiInterface& setHandleStop(StopCallback fptr) { mStopCallback = fptr; return *this; };
|
||||
inline MidiInterface& setHandleActiveSensing(ActiveSensingCallback fptr) { mActiveSensingCallback = fptr; return *this; };
|
||||
inline MidiInterface& setHandleSystemReset(SystemResetCallback fptr) { mSystemResetCallback = fptr; return *this; };
|
||||
inline void setHandleMessage(void (*fptr)(const MidiMessage&)) { mMessageCallback = fptr; };
|
||||
inline void setHandleError(ErrorCallback fptr) { mErrorCallback = fptr; }
|
||||
inline void setHandleActiveSensingTimeout(ActiveSensingTimeoutCallback fptr) { mActiveSensingTimeoutCallback = fptr; }
|
||||
inline void setHandleNoteOff(NoteOffCallback fptr) { mNoteOffCallback = fptr; }
|
||||
inline void setHandleNoteOn(NoteOnCallback fptr) { mNoteOnCallback = fptr; }
|
||||
inline void setHandleAfterTouchPoly(AfterTouchPolyCallback fptr) { mAfterTouchPolyCallback = fptr; }
|
||||
inline void setHandleControlChange(ControlChangeCallback fptr) { mControlChangeCallback = fptr; }
|
||||
inline void setHandleProgramChange(ProgramChangeCallback fptr) { mProgramChangeCallback = fptr; }
|
||||
inline void setHandleAfterTouchChannel(AfterTouchChannelCallback fptr) { mAfterTouchChannelCallback = fptr; }
|
||||
inline void setHandlePitchBend(PitchBendCallback fptr) { mPitchBendCallback = fptr; }
|
||||
inline void setHandleSystemExclusive(SystemExclusiveCallback fptr) { mSystemExclusiveCallback = fptr; }
|
||||
inline void setHandleTimeCodeQuarterFrame(TimeCodeQuarterFrameCallback fptr) { mTimeCodeQuarterFrameCallback = fptr; }
|
||||
inline void setHandleSongPosition(SongPositionCallback fptr) { mSongPositionCallback = fptr; }
|
||||
inline void setHandleSongSelect(SongSelectCallback fptr) { mSongSelectCallback = fptr; }
|
||||
inline void setHandleTuneRequest(TuneRequestCallback fptr) { mTuneRequestCallback = fptr; }
|
||||
inline void setHandleClock(ClockCallback fptr) { mClockCallback = fptr; }
|
||||
inline void setHandleStart(StartCallback fptr) { mStartCallback = fptr; }
|
||||
inline void setHandleTick(TickCallback fptr) { mTickCallback = fptr; }
|
||||
inline void setHandleContinue(ContinueCallback fptr) { mContinueCallback = fptr; }
|
||||
inline void setHandleStop(StopCallback fptr) { mStopCallback = fptr; }
|
||||
inline void setHandleActiveSensing(ActiveSensingCallback fptr) { mActiveSensingCallback = fptr; }
|
||||
inline void setHandleSystemReset(SystemResetCallback fptr) { mSystemResetCallback = fptr; }
|
||||
|
||||
inline MidiInterface& disconnectCallbackFromType(MidiType inType);
|
||||
inline void disconnectCallbackFromType(MidiType inType);
|
||||
|
||||
private:
|
||||
void launchCallback();
|
||||
|
||||
void (*mMessageCallback)(const MidiMessage& message) = nullptr;
|
||||
ErrorCallback mErrorCallback = nullptr;
|
||||
ActiveSensingTimeoutCallback mActiveSensingTimeoutCallback = nullptr;
|
||||
NoteOffCallback mNoteOffCallback = nullptr;
|
||||
NoteOnCallback mNoteOnCallback = nullptr;
|
||||
AfterTouchPolyCallback mAfterTouchPolyCallback = nullptr;
|
||||
|
|
@ -239,9 +241,9 @@ public:
|
|||
inline Thru::Mode getFilterMode() const;
|
||||
inline bool getThruState() const;
|
||||
|
||||
inline MidiInterface& turnThruOn(Thru::Mode inThruFilterMode = Thru::Full);
|
||||
inline MidiInterface& turnThruOff();
|
||||
inline MidiInterface& setThruFilterMode(Thru::Mode inThruFilterMode);
|
||||
inline void turnThruOn(Thru::Mode inThruFilterMode = Thru::Full);
|
||||
inline void turnThruOff();
|
||||
inline void setThruFilterMode(Thru::Mode inThruFilterMode);
|
||||
|
||||
private:
|
||||
void thruFilter(byte inChannel);
|
||||
|
|
@ -254,7 +256,7 @@ private:
|
|||
inline void handleNullVelocityNoteOnAsNoteOff();
|
||||
inline bool inputFilter(Channel inChannel);
|
||||
inline void resetInput();
|
||||
inline void updateLastSentTime();
|
||||
inline void UpdateLastSentTime();
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Transport
|
||||
|
|
@ -282,8 +284,7 @@ private:
|
|||
MidiMessage mMessage;
|
||||
unsigned long mLastMessageSentTime;
|
||||
unsigned long mLastMessageReceivedTime;
|
||||
unsigned long mSenderActiveSensingPeriodicity;
|
||||
bool mReceiverActiveSensingActivated;
|
||||
bool mReceiverActiveSensingActive;
|
||||
int8_t mLastError;
|
||||
|
||||
private:
|
||||
|
|
|
|||
280
src/MIDI.hpp
280
src/MIDI.hpp
|
|
@ -44,11 +44,10 @@ inline MidiInterface<Transport, Settings, Platform>::MidiInterface(Transport& in
|
|||
, mThruFilterMode(Thru::Full)
|
||||
, mLastMessageSentTime(0)
|
||||
, mLastMessageReceivedTime(0)
|
||||
, mSenderActiveSensingPeriodicity(0)
|
||||
, mReceiverActiveSensingActivated(false)
|
||||
, mReceiverActiveSensingActive(false)
|
||||
, mLastError(0)
|
||||
{
|
||||
mSenderActiveSensingPeriodicity = Settings::SenderActiveSensingPeriodicity;
|
||||
static_assert(!(Settings::UseSenderActiveSensing && Settings::UseReceiverActiveSensing), "UseSenderActiveSensing and UseReceiverActiveSensing can't be both set to true.");
|
||||
}
|
||||
|
||||
/*! \brief Destructor for MidiInterface.
|
||||
|
|
@ -69,7 +68,7 @@ inline MidiInterface<Transport, Settings, Platform>::~MidiInterface()
|
|||
- Full thru mirroring
|
||||
*/
|
||||
template<class Transport, class Settings, class Platform>
|
||||
MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings, Platform>::begin(Channel inChannel)
|
||||
void MidiInterface<Transport, Settings, Platform>::begin(Channel inChannel)
|
||||
{
|
||||
// Initialise the Transport layer
|
||||
mTransport.begin();
|
||||
|
|
@ -84,7 +83,8 @@ MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings,
|
|||
mCurrentRpnNumber = 0xffff;
|
||||
mCurrentNrpnNumber = 0xffff;
|
||||
|
||||
mLastMessageSentTime = Platform::now();
|
||||
mLastMessageSentTime =
|
||||
mLastMessageReceivedTime = Platform::now();
|
||||
|
||||
mMessage.valid = false;
|
||||
mMessage.type = InvalidType;
|
||||
|
|
@ -95,8 +95,6 @@ MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings,
|
|||
|
||||
mThruFilterMode = Thru::Full;
|
||||
mThruActivated = mTransport.thruActivated;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
@ -117,38 +115,33 @@ MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings,
|
|||
them thru.
|
||||
*/
|
||||
template<class Transport, class Settings, class Platform>
|
||||
MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings, Platform>::send(const MidiMessage& inMessage)
|
||||
void MidiInterface<Transport, Settings, Platform>::send(const MidiMessage& inMessage)
|
||||
{
|
||||
if (!inMessage.valid)
|
||||
return *this;
|
||||
return;
|
||||
|
||||
if (mTransport.beginTransmission(inMessage.type))
|
||||
{
|
||||
if (inMessage.isSystemRealTime())
|
||||
const StatusByte status = getStatus(inMessage.type, inMessage.channel);
|
||||
mTransport.write(status);
|
||||
|
||||
if (inMessage.type != MidiType::SystemExclusive)
|
||||
{
|
||||
mTransport.write(inMessage.type);
|
||||
} else if (inMessage.isChannelMessage())
|
||||
{
|
||||
const StatusByte status = getStatus(inMessage.type, inMessage.channel);
|
||||
mTransport.write(status);
|
||||
if (inMessage.length > 1) mTransport.write(inMessage.data1);
|
||||
if (inMessage.length > 2) mTransport.write(inMessage.data2);
|
||||
} else if (inMessage.type == MidiType::SystemExclusive)
|
||||
} else
|
||||
{
|
||||
const unsigned size = inMessage.getSysExSize();
|
||||
for (size_t i = 0; i < size; i++)
|
||||
// sysexArray does not contain the start and end tags
|
||||
mTransport.write(MidiType::SystemExclusiveStart);
|
||||
|
||||
for (size_t i = 0; i < inMessage.getSysExSize(); i++)
|
||||
mTransport.write(inMessage.sysexArray[i]);
|
||||
} else // at this point, it it assumed to be a system common message
|
||||
{
|
||||
mTransport.write(inMessage.type);
|
||||
if (inMessage.length > 1) mTransport.write(inMessage.data1);
|
||||
if (inMessage.length > 2) mTransport.write(inMessage.data2);
|
||||
|
||||
mTransport.write(MidiType::SystemExclusiveEnd);
|
||||
}
|
||||
}
|
||||
mTransport.endTransmission();
|
||||
updateLastSentTime();
|
||||
|
||||
return *this;
|
||||
UpdateLastSentTime();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -164,7 +157,7 @@ MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings,
|
|||
from your code, at your own risks.
|
||||
*/
|
||||
template<class Transport, class Settings, class Platform>
|
||||
MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings, Platform>::send(MidiType inType,
|
||||
void MidiInterface<Transport, Settings, Platform>::send(MidiType inType,
|
||||
DataByte inData1,
|
||||
DataByte inData2,
|
||||
Channel inChannel)
|
||||
|
|
@ -176,7 +169,7 @@ MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings,
|
|||
inChannel == MIDI_CHANNEL_OMNI ||
|
||||
inType < 0x80)
|
||||
{
|
||||
return *this; // Don't send anything
|
||||
return; // Don't send anything
|
||||
}
|
||||
// Protection: remove MSBs on data
|
||||
inData1 &= 0x7f;
|
||||
|
|
@ -209,15 +202,13 @@ MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings,
|
|||
}
|
||||
|
||||
mTransport.endTransmission();
|
||||
updateLastSentTime();
|
||||
UpdateLastSentTime();
|
||||
}
|
||||
}
|
||||
else if (inType >= Clock && inType <= SystemReset)
|
||||
{
|
||||
sendRealTime(inType); // System Real-time and 1 byte.
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
@ -232,11 +223,11 @@ MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings,
|
|||
http://www.phys.unsw.edu.au/jw/notes.html
|
||||
*/
|
||||
template<class Transport, class Settings, class Platform>
|
||||
MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings, Platform>::sendNoteOn(DataByte inNoteNumber,
|
||||
void MidiInterface<Transport, Settings, Platform>::sendNoteOn(DataByte inNoteNumber,
|
||||
DataByte inVelocity,
|
||||
Channel inChannel)
|
||||
{
|
||||
return send(NoteOn, inNoteNumber, inVelocity, inChannel);
|
||||
send(NoteOn, inNoteNumber, inVelocity, inChannel);
|
||||
}
|
||||
|
||||
/*! \brief Send a Note Off message
|
||||
|
|
@ -251,11 +242,11 @@ MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings,
|
|||
http://www.phys.unsw.edu.au/jw/notes.html
|
||||
*/
|
||||
template<class Transport, class Settings, class Platform>
|
||||
MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings, Platform>::sendNoteOff(DataByte inNoteNumber,
|
||||
void MidiInterface<Transport, Settings, Platform>::sendNoteOff(DataByte inNoteNumber,
|
||||
DataByte inVelocity,
|
||||
Channel inChannel)
|
||||
{
|
||||
return send(NoteOff, inNoteNumber, inVelocity, inChannel);
|
||||
send(NoteOff, inNoteNumber, inVelocity, inChannel);
|
||||
}
|
||||
|
||||
/*! \brief Send a Program Change message
|
||||
|
|
@ -263,10 +254,10 @@ MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings,
|
|||
\param inChannel The channel on which the message will be sent (1 to 16).
|
||||
*/
|
||||
template<class Transport, class Settings, class Platform>
|
||||
MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings, Platform>::sendProgramChange(DataByte inProgramNumber,
|
||||
void MidiInterface<Transport, Settings, Platform>::sendProgramChange(DataByte inProgramNumber,
|
||||
Channel inChannel)
|
||||
{
|
||||
return send(ProgramChange, inProgramNumber, 0, inChannel);
|
||||
send(ProgramChange, inProgramNumber, 0, inChannel);
|
||||
}
|
||||
|
||||
/*! \brief Send a Control Change message
|
||||
|
|
@ -276,11 +267,11 @@ MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings,
|
|||
@see MidiControlChangeNumber
|
||||
*/
|
||||
template<class Transport, class Settings, class Platform>
|
||||
MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings, Platform>::sendControlChange(DataByte inControlNumber,
|
||||
void MidiInterface<Transport, Settings, Platform>::sendControlChange(DataByte inControlNumber,
|
||||
DataByte inControlValue,
|
||||
Channel inChannel)
|
||||
{
|
||||
return send(ControlChange, inControlNumber, inControlValue, inChannel);
|
||||
send(ControlChange, inControlNumber, inControlValue, inChannel);
|
||||
}
|
||||
|
||||
/*! \brief Send a Polyphonic AfterTouch message (applies to a specified note)
|
||||
|
|
@ -291,11 +282,11 @@ MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings,
|
|||
library, @see sendAfterTouch to send polyphonic and monophonic AfterTouch messages.
|
||||
*/
|
||||
template<class Transport, class Settings, class Platform>
|
||||
MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings, Platform>::sendPolyPressure(DataByte inNoteNumber,
|
||||
void MidiInterface<Transport, Settings, Platform>::sendPolyPressure(DataByte inNoteNumber,
|
||||
DataByte inPressure,
|
||||
Channel inChannel)
|
||||
{
|
||||
return send(AfterTouchPoly, inNoteNumber, inPressure, inChannel);
|
||||
send(AfterTouchPoly, inNoteNumber, inPressure, inChannel);
|
||||
}
|
||||
|
||||
/*! \brief Send a MonoPhonic AfterTouch message (applies to all notes)
|
||||
|
|
@ -303,10 +294,10 @@ MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings,
|
|||
\param inChannel The channel on which the message will be sent (1 to 16).
|
||||
*/
|
||||
template<class Transport, class Settings, class Platform>
|
||||
MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings, Platform>::sendAfterTouch(DataByte inPressure,
|
||||
void MidiInterface<Transport, Settings, Platform>::sendAfterTouch(DataByte inPressure,
|
||||
Channel inChannel)
|
||||
{
|
||||
return send(AfterTouchChannel, inPressure, 0, inChannel);
|
||||
send(AfterTouchChannel, inPressure, 0, inChannel);
|
||||
}
|
||||
|
||||
/*! \brief Send a Polyphonic AfterTouch message (applies to a specified note)
|
||||
|
|
@ -316,11 +307,11 @@ MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings,
|
|||
@see Replaces sendPolyPressure (which is now deprecated).
|
||||
*/
|
||||
template<class Transport, class Settings, class Platform>
|
||||
MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings, Platform>::sendAfterTouch(DataByte inNoteNumber,
|
||||
void MidiInterface<Transport, Settings, Platform>::sendAfterTouch(DataByte inNoteNumber,
|
||||
DataByte inPressure,
|
||||
Channel inChannel)
|
||||
{
|
||||
return send(AfterTouchPoly, inNoteNumber, inPressure, inChannel);
|
||||
send(AfterTouchPoly, inNoteNumber, inPressure, inChannel);
|
||||
}
|
||||
|
||||
/*! \brief Send a Pitch Bend message using a signed integer value.
|
||||
|
|
@ -330,11 +321,11 @@ MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings,
|
|||
\param inChannel The channel on which the message will be sent (1 to 16).
|
||||
*/
|
||||
template<class Transport, class Settings, class Platform>
|
||||
MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings, Platform>::sendPitchBend(int inPitchValue,
|
||||
void MidiInterface<Transport, Settings, Platform>::sendPitchBend(int inPitchValue,
|
||||
Channel inChannel)
|
||||
{
|
||||
const unsigned bend = unsigned(inPitchValue - int(MIDI_PITCHBEND_MIN));
|
||||
return send(PitchBend, (bend & 0x7f), (bend >> 7) & 0x7f, inChannel);
|
||||
send(PitchBend, (bend & 0x7f), (bend >> 7) & 0x7f, inChannel);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -345,12 +336,12 @@ MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings,
|
|||
\param inChannel The channel on which the message will be sent (1 to 16).
|
||||
*/
|
||||
template<class Transport, class Settings, class Platform>
|
||||
MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings, Platform>::sendPitchBend(double inPitchValue,
|
||||
void MidiInterface<Transport, Settings, Platform>::sendPitchBend(double inPitchValue,
|
||||
Channel inChannel)
|
||||
{
|
||||
const int scale = inPitchValue > 0.0 ? MIDI_PITCHBEND_MAX : - MIDI_PITCHBEND_MIN;
|
||||
const int scale = inPitchValue > 0.0 ? MIDI_PITCHBEND_MAX : MIDI_PITCHBEND_MIN;
|
||||
const int value = int(inPitchValue * double(scale));
|
||||
return sendPitchBend(value, inChannel);
|
||||
sendPitchBend(value, inChannel);
|
||||
}
|
||||
|
||||
/*! \brief Generate and send a System Exclusive frame.
|
||||
|
|
@ -363,7 +354,7 @@ MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings,
|
|||
with previous versions of the library.
|
||||
*/
|
||||
template<class Transport, class Settings, class Platform>
|
||||
MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings, Platform>::sendSysEx(unsigned inLength,
|
||||
void MidiInterface<Transport, Settings, Platform>::sendSysEx(unsigned inLength,
|
||||
const byte* inArray,
|
||||
bool inArrayContainsBoundaries)
|
||||
{
|
||||
|
|
@ -381,13 +372,11 @@ MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings,
|
|||
mTransport.write(MidiType::SystemExclusiveEnd);
|
||||
|
||||
mTransport.endTransmission();
|
||||
updateLastSentTime();
|
||||
UpdateLastSentTime();
|
||||
}
|
||||
|
||||
if (Settings::UseRunningStatus)
|
||||
mRunningStatus_TX = InvalidType;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*! \brief Send a Tune Request message.
|
||||
|
|
@ -396,9 +385,9 @@ MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings,
|
|||
it should tune its oscillators (if equipped with any).
|
||||
*/
|
||||
template<class Transport, class Settings, class Platform>
|
||||
MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings, Platform>::sendTuneRequest()
|
||||
void MidiInterface<Transport, Settings, Platform>::sendTuneRequest()
|
||||
{
|
||||
return sendCommon(TuneRequest);
|
||||
sendCommon(TuneRequest);
|
||||
}
|
||||
|
||||
/*! \brief Send a MIDI Time Code Quarter Frame.
|
||||
|
|
@ -408,11 +397,11 @@ MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings,
|
|||
See MIDI Specification for more information.
|
||||
*/
|
||||
template<class Transport, class Settings, class Platform>
|
||||
MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings, Platform>::sendTimeCodeQuarterFrame(DataByte inTypeNibble,
|
||||
void MidiInterface<Transport, Settings, Platform>::sendTimeCodeQuarterFrame(DataByte inTypeNibble,
|
||||
DataByte inValuesNibble)
|
||||
{
|
||||
const byte data = byte((((inTypeNibble & 0x07) << 4) | (inValuesNibble & 0x0f)));
|
||||
return sendTimeCodeQuarterFrame(data);
|
||||
sendTimeCodeQuarterFrame(data);
|
||||
}
|
||||
|
||||
/*! \brief Send a MIDI Time Code Quarter Frame.
|
||||
|
|
@ -422,25 +411,25 @@ MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings,
|
|||
you can send the byte here.
|
||||
*/
|
||||
template<class Transport, class Settings, class Platform>
|
||||
MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings, Platform>::sendTimeCodeQuarterFrame(DataByte inData)
|
||||
void MidiInterface<Transport, Settings, Platform>::sendTimeCodeQuarterFrame(DataByte inData)
|
||||
{
|
||||
return sendCommon(TimeCodeQuarterFrame, inData);
|
||||
sendCommon(TimeCodeQuarterFrame, inData);
|
||||
}
|
||||
|
||||
/*! \brief Send a Song Position Pointer message.
|
||||
\param inBeats The number of beats since the start of the song.
|
||||
*/
|
||||
template<class Transport, class Settings, class Platform>
|
||||
MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings, Platform>::sendSongPosition(unsigned inBeats)
|
||||
void MidiInterface<Transport, Settings, Platform>::sendSongPosition(unsigned inBeats)
|
||||
{
|
||||
return sendCommon(SongPosition, inBeats);
|
||||
sendCommon(SongPosition, inBeats);
|
||||
}
|
||||
|
||||
/*! \brief Send a Song Select message */
|
||||
template<class Transport, class Settings, class Platform>
|
||||
MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings, Platform>::sendSongSelect(DataByte inSongNumber)
|
||||
void MidiInterface<Transport, Settings, Platform>::sendSongSelect(DataByte inSongNumber)
|
||||
{
|
||||
return sendCommon(SongSelect, inSongNumber);
|
||||
sendCommon(SongSelect, inSongNumber);
|
||||
}
|
||||
|
||||
/*! \brief Send a Common message. Common messages reset the running status.
|
||||
|
|
@ -451,7 +440,7 @@ MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings,
|
|||
\param inData1 The byte that goes with the common message.
|
||||
*/
|
||||
template<class Transport, class Settings, class Platform>
|
||||
MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings, Platform>::sendCommon(MidiType inType, unsigned inData1)
|
||||
void MidiInterface<Transport, Settings, Platform>::sendCommon(MidiType inType, unsigned inData1)
|
||||
{
|
||||
switch (inType)
|
||||
{
|
||||
|
|
@ -462,7 +451,7 @@ MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings,
|
|||
break;
|
||||
default:
|
||||
// Invalid Common marker
|
||||
return *this;
|
||||
return;
|
||||
}
|
||||
|
||||
if (mTransport.beginTransmission(inType))
|
||||
|
|
@ -482,19 +471,15 @@ MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings,
|
|||
break;
|
||||
case TuneRequest:
|
||||
break;
|
||||
// LCOV_EXCL_START - Coverage blind spot
|
||||
default:
|
||||
break;
|
||||
// LCOV_EXCL_STOP
|
||||
break; // LCOV_EXCL_LINE - Coverage blind spot
|
||||
}
|
||||
mTransport.endTransmission();
|
||||
updateLastSentTime();
|
||||
UpdateLastSentTime();
|
||||
}
|
||||
|
||||
if (Settings::UseRunningStatus)
|
||||
mRunningStatus_TX = InvalidType;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*! \brief Send a Real Time (one byte) message.
|
||||
|
|
@ -504,7 +489,7 @@ MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings,
|
|||
@see MidiType
|
||||
*/
|
||||
template<class Transport, class Settings, class Platform>
|
||||
MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings, Platform>::sendRealTime(MidiType inType)
|
||||
void MidiInterface<Transport, Settings, Platform>::sendRealTime(MidiType inType)
|
||||
{
|
||||
// Do not invalidate Running Status for real-time messages
|
||||
// as they can be interleaved within any message.
|
||||
|
|
@ -521,15 +506,13 @@ MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings,
|
|||
{
|
||||
mTransport.write((byte)inType);
|
||||
mTransport.endTransmission();
|
||||
updateLastSentTime();
|
||||
UpdateLastSentTime();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Invalid Real Time marker
|
||||
break;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*! \brief Start a Registered Parameter Number frame.
|
||||
|
|
@ -537,7 +520,7 @@ MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings,
|
|||
\param inChannel The channel on which the message will be sent (1 to 16).
|
||||
*/
|
||||
template<class Transport, class Settings, class Platform>
|
||||
inline MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings, Platform>::beginRpn(unsigned inNumber,
|
||||
inline void MidiInterface<Transport, Settings, Platform>::beginRpn(unsigned inNumber,
|
||||
Channel inChannel)
|
||||
{
|
||||
if (mCurrentRpnNumber != inNumber)
|
||||
|
|
@ -548,8 +531,6 @@ inline MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Se
|
|||
sendControlChange(RPNMSB, numMsb, inChannel);
|
||||
mCurrentRpnNumber = inNumber;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*! \brief Send a 14-bit value for the currently selected RPN number.
|
||||
|
|
@ -557,15 +538,13 @@ inline MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Se
|
|||
\param inChannel The channel on which the message will be sent (1 to 16).
|
||||
*/
|
||||
template<class Transport, class Settings, class Platform>
|
||||
inline MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings, Platform>::sendRpnValue(unsigned inValue,
|
||||
inline void MidiInterface<Transport, Settings, Platform>::sendRpnValue(unsigned inValue,
|
||||
Channel inChannel)
|
||||
{;
|
||||
const byte valMsb = 0x7f & (inValue >> 7);
|
||||
const byte valLsb = 0x7f & inValue;
|
||||
sendControlChange(DataEntryMSB, valMsb, inChannel);
|
||||
sendControlChange(DataEntryLSB, valLsb, inChannel);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*! \brief Send separate MSB/LSB values for the currently selected RPN number.
|
||||
|
|
@ -574,38 +553,32 @@ inline MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Se
|
|||
\param inChannel The channel on which the message will be sent (1 to 16).
|
||||
*/
|
||||
template<class Transport, class Settings, class Platform>
|
||||
inline MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings, Platform>::sendRpnValue(byte inMsb,
|
||||
inline void MidiInterface<Transport, Settings, Platform>::sendRpnValue(byte inMsb,
|
||||
byte inLsb,
|
||||
Channel inChannel)
|
||||
{
|
||||
sendControlChange(DataEntryMSB, inMsb, inChannel);
|
||||
sendControlChange(DataEntryLSB, inLsb, inChannel);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* \brief Increment the value of the currently selected RPN number by the specified amount.
|
||||
\param inAmount The amount to add to the currently selected RPN value.
|
||||
*/
|
||||
template<class Transport, class Settings, class Platform>
|
||||
inline MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings, Platform>::sendRpnIncrement(byte inAmount,
|
||||
inline void MidiInterface<Transport, Settings, Platform>::sendRpnIncrement(byte inAmount,
|
||||
Channel inChannel)
|
||||
{
|
||||
sendControlChange(DataIncrement, inAmount, inChannel);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* \brief Decrement the value of the currently selected RPN number by the specified amount.
|
||||
\param inAmount The amount to subtract to the currently selected RPN value.
|
||||
*/
|
||||
template<class Transport, class Settings, class Platform>
|
||||
inline MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings, Platform>::sendRpnDecrement(byte inAmount,
|
||||
inline void MidiInterface<Transport, Settings, Platform>::sendRpnDecrement(byte inAmount,
|
||||
Channel inChannel)
|
||||
{
|
||||
sendControlChange(DataDecrement, inAmount, inChannel);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*! \brief Terminate an RPN frame.
|
||||
|
|
@ -613,13 +586,11 @@ This will send a Null Function to deselect the currently selected RPN.
|
|||
\param inChannel The channel on which the message will be sent (1 to 16).
|
||||
*/
|
||||
template<class Transport, class Settings, class Platform>
|
||||
inline MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings, Platform>::endRpn(Channel inChannel)
|
||||
inline void MidiInterface<Transport, Settings, Platform>::endRpn(Channel inChannel)
|
||||
{
|
||||
sendControlChange(RPNLSB, 0x7f, inChannel);
|
||||
sendControlChange(RPNMSB, 0x7f, inChannel);
|
||||
mCurrentRpnNumber = 0xffff;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -629,7 +600,7 @@ inline MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Se
|
|||
\param inChannel The channel on which the message will be sent (1 to 16).
|
||||
*/
|
||||
template<class Transport, class Settings, class Platform>
|
||||
inline MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings, Platform>::beginNrpn(unsigned inNumber,
|
||||
inline void MidiInterface<Transport, Settings, Platform>::beginNrpn(unsigned inNumber,
|
||||
Channel inChannel)
|
||||
{
|
||||
if (mCurrentNrpnNumber != inNumber)
|
||||
|
|
@ -640,8 +611,6 @@ inline MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Se
|
|||
sendControlChange(NRPNMSB, numMsb, inChannel);
|
||||
mCurrentNrpnNumber = inNumber;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*! \brief Send a 14-bit value for the currently selected NRPN number.
|
||||
|
|
@ -649,15 +618,13 @@ inline MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Se
|
|||
\param inChannel The channel on which the message will be sent (1 to 16).
|
||||
*/
|
||||
template<class Transport, class Settings, class Platform>
|
||||
inline MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings, Platform>::sendNrpnValue(unsigned inValue,
|
||||
inline void MidiInterface<Transport, Settings, Platform>::sendNrpnValue(unsigned inValue,
|
||||
Channel inChannel)
|
||||
{
|
||||
{;
|
||||
const byte valMsb = 0x7f & (inValue >> 7);
|
||||
const byte valLsb = 0x7f & inValue;
|
||||
sendControlChange(DataEntryMSB, valMsb, inChannel);
|
||||
sendControlChange(DataEntryLSB, valLsb, inChannel);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*! \brief Send separate MSB/LSB values for the currently selected NRPN number.
|
||||
|
|
@ -666,38 +633,32 @@ inline MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Se
|
|||
\param inChannel The channel on which the message will be sent (1 to 16).
|
||||
*/
|
||||
template<class Transport, class Settings, class Platform>
|
||||
inline MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings, Platform>::sendNrpnValue(byte inMsb,
|
||||
inline void MidiInterface<Transport, Settings, Platform>::sendNrpnValue(byte inMsb,
|
||||
byte inLsb,
|
||||
Channel inChannel)
|
||||
{
|
||||
sendControlChange(DataEntryMSB, inMsb, inChannel);
|
||||
sendControlChange(DataEntryLSB, inLsb, inChannel);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* \brief Increment the value of the currently selected NRPN number by the specified amount.
|
||||
\param inAmount The amount to add to the currently selected NRPN value.
|
||||
*/
|
||||
template<class Transport, class Settings, class Platform>
|
||||
inline MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings, Platform>::sendNrpnIncrement(byte inAmount,
|
||||
inline void MidiInterface<Transport, Settings, Platform>::sendNrpnIncrement(byte inAmount,
|
||||
Channel inChannel)
|
||||
{
|
||||
sendControlChange(DataIncrement, inAmount, inChannel);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* \brief Decrement the value of the currently selected NRPN number by the specified amount.
|
||||
\param inAmount The amount to subtract to the currently selected NRPN value.
|
||||
*/
|
||||
template<class Transport, class Settings, class Platform>
|
||||
inline MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings, Platform>::sendNrpnDecrement(byte inAmount,
|
||||
inline void MidiInterface<Transport, Settings, Platform>::sendNrpnDecrement(byte inAmount,
|
||||
Channel inChannel)
|
||||
{
|
||||
sendControlChange(DataDecrement, inAmount, inChannel);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*! \brief Terminate an NRPN frame.
|
||||
|
|
@ -705,20 +666,11 @@ This will send a Null Function to deselect the currently selected NRPN.
|
|||
\param inChannel The channel on which the message will be sent (1 to 16).
|
||||
*/
|
||||
template<class Transport, class Settings, class Platform>
|
||||
inline MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings, Platform>::endNrpn(Channel inChannel)
|
||||
inline void MidiInterface<Transport, Settings, Platform>::endNrpn(Channel inChannel)
|
||||
{
|
||||
sendControlChange(NRPNLSB, 0x7f, inChannel);
|
||||
sendControlChange(NRPNMSB, 0x7f, inChannel);
|
||||
mCurrentNrpnNumber = 0xffff;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class Transport, class Settings, class Platform>
|
||||
inline void MidiInterface<Transport, Settings, Platform>::updateLastSentTime()
|
||||
{
|
||||
if (Settings::UseSenderActiveSensing && mSenderActiveSensingPeriodicity)
|
||||
mLastMessageSentTime = Platform::now();
|
||||
}
|
||||
|
||||
/*! @} */ // End of doc group MIDI Output
|
||||
|
|
@ -760,27 +712,32 @@ template<class Transport, class Settings, class Platform>
|
|||
inline bool MidiInterface<Transport, Settings, Platform>::read(Channel inChannel)
|
||||
{
|
||||
#ifndef RegionActiveSending
|
||||
|
||||
// Active Sensing. This message is intended to be sent
|
||||
// repeatedly to tell the receiver that a connection is alive. Use
|
||||
// of this message is optional. When initially received, the
|
||||
// receiver will expect to receive another Active Sensing
|
||||
// message each 300ms (max), and if it does not then it will
|
||||
// assume that the connection has been terminated. At
|
||||
// termination, the receiver will turn off all voices and return to
|
||||
// normal (non- active sensing) operation.
|
||||
if (Settings::UseSenderActiveSensing && (mSenderActiveSensingPeriodicity > 0) && (Platform::now() - mLastMessageSentTime) > mSenderActiveSensingPeriodicity)
|
||||
// of this message is optional.
|
||||
if (Settings::UseSenderActiveSensing)
|
||||
{
|
||||
sendActiveSensing();
|
||||
mLastMessageSentTime = Platform::now();
|
||||
// Send ActiveSensing <Settings::ActiveSensingPeriodicity> ms after the last command
|
||||
if ((Platform::now() - mLastMessageSentTime) > Settings::SenderActiveSensingPeriodicity)
|
||||
sendActiveSensing();
|
||||
}
|
||||
|
||||
if (Settings::UseReceiverActiveSensing && mReceiverActiveSensingActivated && (mLastMessageReceivedTime + ActiveSensingTimeout < Platform::now()))
|
||||
// Once an Active Sensing message is received, the unit will begin monitoring
|
||||
// the intervalbetween all subsequent messages. If there is an interval of 420 ms
|
||||
// or longer betweenmessages while monitoring is active, the same processing
|
||||
// as when All Sound Off, All Notes Off,and Reset All Controllers messages are
|
||||
// received will be carried out. The unit will then stopmonitoring the message interval.
|
||||
if (Settings::UseReceiverActiveSensing && mReceiverActiveSensingActive)
|
||||
{
|
||||
mReceiverActiveSensingActivated = false;
|
||||
if ((Platform::now() - mLastMessageReceivedTime > Settings::ReceiverActiveSensingTimeout))
|
||||
{
|
||||
mReceiverActiveSensingActive = false;
|
||||
|
||||
mLastError |= 1UL << ErrorActiveSensingTimeout; // set the ErrorActiveSensingTimeout bit
|
||||
if (mErrorCallback)
|
||||
mErrorCallback(mLastError);
|
||||
// its up to the handler to send the stop processing messages
|
||||
// (also, no clue what the channel is on which to send them)
|
||||
mActiveSensingTimeoutCallback(mReceiverActiveSensingActive);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -792,25 +749,18 @@ inline bool MidiInterface<Transport, Settings, Platform>::read(Channel inChannel
|
|||
|
||||
#ifndef RegionActiveSending
|
||||
|
||||
if (Settings::UseReceiverActiveSensing && mMessage.type == ActiveSensing)
|
||||
if (Settings::UseReceiverActiveSensing)
|
||||
{
|
||||
// When an ActiveSensing message is received, the time keeping is activated.
|
||||
// When a timeout occurs, an error message is send and time keeping ends.
|
||||
mReceiverActiveSensingActivated = true;
|
||||
mLastMessageReceivedTime = Platform::now();
|
||||
|
||||
// is ErrorActiveSensingTimeout bit in mLastError on
|
||||
if (mLastError & (1 << (ErrorActiveSensingTimeout - 1)))
|
||||
if (mMessage.type == ActiveSensing && !mReceiverActiveSensingActive)
|
||||
{
|
||||
mLastError &= ~(1UL << ErrorActiveSensingTimeout); // clear the ErrorActiveSensingTimeout bit
|
||||
if (mErrorCallback)
|
||||
mErrorCallback(mLastError);
|
||||
mReceiverActiveSensingActive = true;
|
||||
|
||||
mActiveSensingTimeoutCallback(mReceiverActiveSensingActive);
|
||||
}
|
||||
}
|
||||
|
||||
// Keep the time of the last received message, so we can check for the timeout
|
||||
if (Settings::UseReceiverActiveSensing && mReceiverActiveSensingActivated)
|
||||
mLastMessageReceivedTime = Platform::now();
|
||||
|
||||
#endif
|
||||
|
||||
handleNullVelocityNoteOnAsNoteOff();
|
||||
|
|
@ -1028,10 +978,9 @@ bool MidiInterface<Transport, Settings, Platform>::parse()
|
|||
resetInput();
|
||||
return false;
|
||||
}
|
||||
// LCOV_EXCL_START - Coverage blind spot
|
||||
|
||||
default:
|
||||
break;
|
||||
// LCOV_EXCL_STOP
|
||||
break; // LCOV_EXCL_LINE - Coverage blind spot
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1086,7 +1035,6 @@ bool MidiInterface<Transport, Settings, Platform>::parse()
|
|||
mMessage.data1 = mPendingMessage[1];
|
||||
// Save data2 only if applicable
|
||||
mMessage.data2 = mPendingMessageExpectedLength == 3 ? mPendingMessage[2] : 0;
|
||||
mMessage.length = mPendingMessageExpectedLength;
|
||||
|
||||
// Reset local variables
|
||||
mPendingMessageIndex = 0;
|
||||
|
|
@ -1252,11 +1200,9 @@ inline Channel MidiInterface<Transport, Settings, Platform>::getInputChannel() c
|
|||
if you want to listen to all channels, and MIDI_CHANNEL_OFF to disable input.
|
||||
*/
|
||||
template<class Transport, class Settings, class Platform>
|
||||
inline MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings, Platform>::setInputChannel(Channel inChannel)
|
||||
inline void MidiInterface<Transport, Settings, Platform>::setInputChannel(Channel inChannel)
|
||||
{
|
||||
mInputChannel = inChannel;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
@ -1311,7 +1257,7 @@ bool MidiInterface<Transport, Settings, Platform>::isChannelMessage(MidiType inT
|
|||
When a message of this type is received, no function will be called.
|
||||
*/
|
||||
template<class Transport, class Settings, class Platform>
|
||||
MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings, Platform>::disconnectCallbackFromType(MidiType inType)
|
||||
void MidiInterface<Transport, Settings, Platform>::disconnectCallbackFromType(MidiType inType)
|
||||
{
|
||||
switch (inType)
|
||||
{
|
||||
|
|
@ -1337,8 +1283,6 @@ MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings,
|
|||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*! @} */ // End of doc group MIDI Callbacks
|
||||
|
|
@ -1381,11 +1325,9 @@ void MidiInterface<Transport, Settings, Platform>::launchCallback()
|
|||
|
||||
case SystemReset: if (mSystemResetCallback != nullptr) mSystemResetCallback(); break;
|
||||
|
||||
// LCOV_EXCL_START - Unreacheable code, but prevents unhandled case warning.
|
||||
case InvalidType:
|
||||
default:
|
||||
break;
|
||||
// LCOV_EXCL_STOP
|
||||
break; // LCOV_EXCL_LINE - Unreacheable code, but prevents unhandled case warning.
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1405,12 +1347,10 @@ void MidiInterface<Transport, Settings, Platform>::launchCallback()
|
|||
@see Thru::Mode
|
||||
*/
|
||||
template<class Transport, class Settings, class Platform>
|
||||
inline MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings, Platform>::setThruFilterMode(Thru::Mode inThruFilterMode)
|
||||
inline void MidiInterface<Transport, Settings, Platform>::setThruFilterMode(Thru::Mode inThruFilterMode)
|
||||
{
|
||||
mThruFilterMode = inThruFilterMode;
|
||||
mThruActivated = mThruFilterMode != Thru::Off;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class Transport, class Settings, class Platform>
|
||||
|
|
@ -1426,23 +1366,25 @@ inline bool MidiInterface<Transport, Settings, Platform>::getThruState() const
|
|||
}
|
||||
|
||||
template<class Transport, class Settings, class Platform>
|
||||
inline MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings, Platform>::turnThruOn(Thru::Mode inThruFilterMode)
|
||||
inline void MidiInterface<Transport, Settings, Platform>::turnThruOn(Thru::Mode inThruFilterMode)
|
||||
{
|
||||
mThruActivated = true;
|
||||
mThruFilterMode = inThruFilterMode;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class Transport, class Settings, class Platform>
|
||||
inline MidiInterface<Transport, Settings, Platform>& MidiInterface<Transport, Settings, Platform>::turnThruOff()
|
||||
inline void MidiInterface<Transport, Settings, Platform>::turnThruOff()
|
||||
{
|
||||
mThruActivated = false;
|
||||
mThruFilterMode = Thru::Off;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class Transport, class Settings, class Platform>
|
||||
inline void MidiInterface<Transport, Settings, Platform>::UpdateLastSentTime()
|
||||
{
|
||||
if (Settings::UseSenderActiveSensing)
|
||||
mLastMessageSentTime = Platform::now();
|
||||
}
|
||||
|
||||
/*! @} */ // End of doc group MIDI Thru
|
||||
|
||||
|
|
|
|||
|
|
@ -46,10 +46,6 @@ BEGIN_MIDI_NAMESPACE
|
|||
#define MIDI_PITCHBEND_MIN -8192
|
||||
#define MIDI_PITCHBEND_MAX 8191
|
||||
|
||||
/*! Receiving Active Sensing
|
||||
*/
|
||||
static const uint16_t ActiveSensingTimeout = 300;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Type definitions
|
||||
|
||||
|
|
@ -61,13 +57,13 @@ typedef byte FilterMode;
|
|||
// -----------------------------------------------------------------------------
|
||||
// Errors
|
||||
static const uint8_t ErrorParse = 0;
|
||||
static const uint8_t ErrorActiveSensingTimeout = 1;
|
||||
static const uint8_t WarningSplitSysEx = 2;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Aliasing
|
||||
|
||||
using ErrorCallback = void (*)(int8_t);
|
||||
using ActiveSensingTimeoutCallback = void (*)(bool);
|
||||
using NoteOffCallback = void (*)(Channel channel, byte note, byte velocity);
|
||||
using NoteOnCallback = void (*)(Channel channel, byte note, byte velocity);
|
||||
using AfterTouchPolyCallback = void (*)(Channel channel, byte note, byte velocity);
|
||||
|
|
@ -164,22 +160,8 @@ enum MidiControlChangeNumber: uint8_t
|
|||
GeneralPurposeController2 = 17,
|
||||
GeneralPurposeController3 = 18,
|
||||
GeneralPurposeController4 = 19,
|
||||
// CC20 to CC31 undefined
|
||||
BankSelectLSB = 32,
|
||||
ModulationWheelLSB = 33,
|
||||
BreathControllerLSB = 34,
|
||||
// CC35 undefined
|
||||
FootControllerLSB = 36,
|
||||
PortamentoTimeLSB = 37,
|
||||
|
||||
DataEntryLSB = 38,
|
||||
ChannelVolumeLSB = 39,
|
||||
BalanceLSB = 40,
|
||||
// CC41 undefined
|
||||
PanLSB = 42,
|
||||
ExpressionControllerLSB = 43,
|
||||
EffectControl1LSB = 44,
|
||||
EffectControl2LSB = 45,
|
||||
// CC46 to CC63 undefined
|
||||
|
||||
// Switches ----------------------------------------------------------------
|
||||
Sustain = 64,
|
||||
|
|
@ -217,7 +199,6 @@ enum MidiControlChangeNumber: uint8_t
|
|||
NRPNMSB = 99, ///< Non-Registered Parameter Number (MSB)
|
||||
RPNLSB = 100, ///< Registered Parameter Number (LSB)
|
||||
RPNMSB = 101, ///< Registered Parameter Number (MSB)
|
||||
// CC102 to CC119 undefined
|
||||
|
||||
// Channel Mode messages ---------------------------------------------------
|
||||
AllSoundOff = 120,
|
||||
|
|
|
|||
|
|
@ -54,20 +54,6 @@ struct Message
|
|||
memset(sysexArray, 0, sSysExMaxSize * sizeof(DataByte));
|
||||
}
|
||||
|
||||
inline Message(const Message& inOther)
|
||||
: channel(inOther.channel)
|
||||
, type(inOther.type)
|
||||
, data1(inOther.data1)
|
||||
, data2(inOther.data2)
|
||||
, valid(inOther.valid)
|
||||
, length(inOther.length)
|
||||
{
|
||||
if (type == midi::SystemExclusive)
|
||||
{
|
||||
memcpy(sysexArray, inOther.sysexArray, sSysExMaxSize * sizeof(DataByte));
|
||||
}
|
||||
}
|
||||
|
||||
/*! The maximum size for the System Exclusive array.
|
||||
*/
|
||||
static const unsigned sSysExMaxSize = SysExMaxSize;
|
||||
|
|
@ -108,24 +94,12 @@ struct Message
|
|||
/*! Total Length of the message.
|
||||
*/
|
||||
unsigned length;
|
||||
|
||||
|
||||
inline unsigned getSysExSize() const
|
||||
{
|
||||
const unsigned size = unsigned(data2) << 8 | data1;
|
||||
return size > sSysExMaxSize ? sSysExMaxSize : size;
|
||||
}
|
||||
inline bool isSystemRealTime () const
|
||||
{
|
||||
return (type & 0xf8) == 0xf8;
|
||||
}
|
||||
inline bool isSystemCommon () const
|
||||
{
|
||||
return (type & 0xf8) == 0xf0;
|
||||
}
|
||||
inline bool isChannelMessage () const
|
||||
{
|
||||
return (type & 0xf0) != 0xf0;
|
||||
}
|
||||
};
|
||||
|
||||
END_MIDI_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -72,18 +72,15 @@ struct DefaultSettings
|
|||
*/
|
||||
static const unsigned SysExMaxSize = 128;
|
||||
|
||||
/*! Global switch to turn on/off sender ActiveSensing
|
||||
Set to true to send ActiveSensing
|
||||
Set to false will not send ActiveSensing message (will also save memory)
|
||||
/*! Global switch to turn on/off sending and receiving ActiveSensing
|
||||
Set to true to activate ActiveSensing
|
||||
Set to false will not send/receive ActiveSensing message (will also save 236 bytes of memory)
|
||||
|
||||
When setting UseActiveSensing to true, MIDI.read() *must* be called
|
||||
as often as possible (1000 / ActiveSensingPeriodicity per second).
|
||||
*/
|
||||
static const bool UseSenderActiveSensing = false;
|
||||
|
||||
/*! Global switch to turn on/off receiver ActiveSensing
|
||||
Set to true to check for message timeouts (via ErrorCallback)
|
||||
Set to false will not check if chained device are still alive (if they use ActiveSensing) (will also save memory)
|
||||
*/
|
||||
static const bool UseReceiverActiveSensing = false;
|
||||
|
||||
/*! Active Sensing is intended to be sent
|
||||
repeatedly by the sender to tell the receiver that a connection is alive. Use
|
||||
of this message is optional. When initially received, the
|
||||
|
|
@ -94,11 +91,20 @@ struct DefaultSettings
|
|||
normal (non- active sensing) operation.
|
||||
|
||||
Typical value is 250 (ms) - an Active Sensing command is send every 250ms.
|
||||
(All Roland devices send Active Sensing every 250ms)
|
||||
|
||||
Setting this field to 0 will disable sending MIDI active sensing.
|
||||
(Most Roland devices send Active Sensing every 250ms)
|
||||
*/
|
||||
static const uint16_t SenderActiveSensingPeriodicity = 0;
|
||||
static const uint16_t SenderActiveSensingPeriodicity = 300;
|
||||
|
||||
/*! Once an Active Sensing message is received, the unit will begin monitoring
|
||||
the intervalbetween all subsequent messages. If there is an interval of ActiveSensingPeriodicity ms
|
||||
or longer betweenmessages while monitoring is active, the same processing
|
||||
as when All Sound Off, All Notes Off,and Reset All Controllers messages are
|
||||
received will be carried out. The unit will then stopmonitoring the message interval.
|
||||
*/
|
||||
static const bool UseReceiverActiveSensing = false;
|
||||
|
||||
static const uint16_t ReceiverActiveSensingTimeout = 300;
|
||||
|
||||
};
|
||||
|
||||
END_MIDI_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -63,11 +63,6 @@ public:
|
|||
#endif
|
||||
}
|
||||
|
||||
void end()
|
||||
{
|
||||
mSerial.end();
|
||||
}
|
||||
|
||||
bool beginTransmission(MidiType)
|
||||
{
|
||||
return true;
|
||||
|
|
@ -121,10 +116,11 @@ END_MIDI_NAMESPACE
|
|||
#endif
|
||||
|
||||
/*! \brief Create an instance of the library attached to a serial port with
|
||||
custom settings.
|
||||
custom MIDI settings (not to be confused with modified Serial Settings, like BaudRate)
|
||||
@see DefaultSettings
|
||||
@see MIDI_CREATE_INSTANCE
|
||||
*/
|
||||
#define MIDI_CREATE_CUSTOM_INSTANCE(Type, SerialPort, Name, Settings) \
|
||||
MIDI_NAMESPACE::SerialMIDI<Type> serial##Name(SerialPort);\
|
||||
MIDI_NAMESPACE::MidiInterface<MIDI_NAMESPACE::SerialMIDI<Type>, Settings> Name((MIDI_NAMESPACE::SerialMIDI<Type>&)serial##Name);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue