I want to create a MutableList of alphabets form A to Z but so far I can only think of the following method as the shortest one without writing each and every alphabet.
fun main()
{
var alphabets: MutableList<Char> = mutableListOf()
for (a in 'A'..'Z')
{
alphabets.add(a)
}
print(alphabets)
}
So I wanted to know if there is any Lambda implementation or shorter method for the same?
You can use CharRange() or using .. operator to create a range.
For example:
val alphabets = ('A'..'Z').toMutableList()
print(alphabets)
// [A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z]
or
val alphabets = CharRange('A','Z').toMutableList()
print(alphabets)
// [A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z]
Alternatively, you can use ('a'..'z').joinToString("").
val abc = ('a'..'z').joinToString("")
println(abc) //abcdefghijklmnopqrstuvwxyz
You can perform the same functions on a string in Kotlin as you can perform on a list of characters
For example:
for (i in abc) { println(i) }
This lists each alphabet individually on a new line just as it would if you converted it into a list.
You can use rangeTo extension function as below
private val alphabets = ('A').rangeTo('Z').toMutableList()
println(alphabets)
[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z]
I am looking at some of the examples of midi output using core midi.
Specifically this question
and this
I have code that works based on these in objC and I now want to try to translate that to swift.
the line I least understand is this one: MIDIPacketList* pktList = (MIDIPacketList*) pktBuffer;
I read this as declaring a pointer pktlist of type MIDIPacketList and assigning it the value of pktBuffer, cast to the type MIDIPacketList
I'm new to C and objC and this makes no sense to me.
MIDIPacketList is a struct defined here:
in what way does it make sense to cast a bytearray to the struct type MIDIPacketList and what is this trying to achieve? I guess it is trying to define the size of the packet list, but why do we need to do that here, and how does this do it anyway? why is it not sufficient to do it with MIDIPacketListAdd as happens a few lines later?
here is my attempt at a midi output class in swift - can anyone see what is going wrong? this code gives no errors in Xcode until it is run. I have a working version of this in objC, but i can't get the size of the packet list defined in swift. (at least I think that's the problem)
import Foundation
import CoreMIDI
class MidiOutClass {
var midiClient = MIDIClientRef()
var midiSource = MIDIEndpointRef()
func openOutput() {
MIDIClientCreate("MIDI client", nil, nil, &midiClient)
MIDISourceCreate(midiClient, "MIDI Source",&midiSource)
println("midi out opened")//should only do this if successful
}
func noteOn(channel: Int, note: Int, velocity:Int) {
midisend((0x90+channel), note: note, value: velocity)
}
func polyAfter(channel: Int, note: Int, value:Int) {
midisend((0xA0+channel), note: note, value: value)
}
func noteOff(channel: Int, note: Int) {
midisend((0x90+channel), note: note, value: 0 )
}
func midisend(status:Int, note: Int, value:Int) {
var packet: UnsafeMutablePointer<MIDIPacket> = nil
//var buffer = [Byte](count:1024, repeatedValue: 0)
//this is the array I'm trying to use in a similar way to the obj C.
var packetList: UnsafeMutablePointer<MIDIPacketList> = nil
let midiDataToSend:[Byte] = [Byte(status), Byte(note), Byte(value)];
packet = MIDIPacketListInit(packetList);
packet = MIDIPacketListAdd(packetList, 1024, packet, 0, 3, midiDataToSend);
if (packet == nil ) {
println("failed to send the midi.")
} else {
MIDIReceived(midiSource, packetList)
println("sent some stuff")
}
}
}//end MidiOutClass
I found an answer at this question
the byte array in the objC version is a nasty hack to allocate some memory to the packetList
here's my revised code, which now works.
func midisend(status:Int, note: Int, value:Int) {
var packet = UnsafeMutablePointer<MIDIPacket>.alloc(1)
var packetList = UnsafeMutablePointer<MIDIPacketList>.alloc(1)
let midiDataToSend:[Byte] = [Byte(status), Byte(note), Byte(value)];
packet = MIDIPacketListInit(packetList);
packet = MIDIPacketListAdd(packetList, 1024, packet, 0, 3, midiDataToSend);
if (packet == nil ) {
println("failed to send the midi.")
} else {
MIDIReceived(midiSource, packetList)
println("sent some stuff")
}
packet.destroy()
//packet.dealloc(1)
packetList.destroy()
packetList.dealloc(1)
}
However, the commented out dealloc seems to be unnecessary, I'm not exactly sure why yet. Does MIDIReceived take care of it?
If anyone has a better solution - maybe without using pointers at all, please post it!
This is how I ended up going about it. I used the example of the byte buffer as found in various C / ObjC examples online, but I found I had to allocate a little bit more space for the MIDIPacketList struct itself.
A MidiEvent is just a UInt8 array. For usual MIDI events, it has a length of 3 bytes: (Status, Data, Data).
/// A UInt8 array, usually 3 bytes long
public typealias MidiEvent = [UInt8]
extension MIDIPacketList {
init(midiEvents: [MidiEvent]) {
let timestamp = MIDITimeStamp(0) // do it now
let totalBytesInAllEvents = midiEvents.reduce(0) { total, event in
return total + event.count
}
// Without this, we'd run out of space for the last few MidiEvents
let listSize = MemoryLayout<MIDIPacketList>.size + totalBytesInAllEvents
// CoreMIDI supports up to 65536 bytes, but in practical tests it seems
// certain devices accept much less than that at a time. Unless you're
// turning on / off ALL notes at once, 256 bytes should be plenty.
assert(totalBytesInAllEvents < 256,
"The packet list was too long! Split your data into multiple lists.")
// Allocate space for a certain number of bytes
let byteBuffer = UnsafeMutablePointer<UInt8>.allocate(capacity: listSize)
// Use that space for our MIDIPacketList
self = byteBuffer.withMemoryRebound(to: MIDIPacketList.self, capacity: 1) { packetList -> MIDIPacketList in
var packet = MIDIPacketListInit(packetList)
midiEvents.forEach { event in
packet = MIDIPacketListAdd(packetList, listSize, packet, timestamp, event.count, event)
}
return packetList.pointee
}
byteBuffer.deallocate() // release the manually managed memory
}
}
So if you're just sending one midi note, it'd look something like this. This example would send a NoteOn message to the Middle C on Channel 1 with a velocity of 100. You should use helper functions to make these MidiEvents though, rather than hard coding them ;)
var packets = MIDIPacketList(midiEvents: [[0x90, 60, 100]])
MIDISend(clientOutputPort, destination, &packetList)
I have also used the above routine for sending midi commands from my app to internal synths running in the background like iMini, Z3TA+, Sunrizer, etc. but I couldn't get rid of memory leaks. This version has no unsafe pointers and allocs. It works without the dreaded memory leaks.
static var z: UInt8 = 0 // initalize tuple with 256 x this UInt8 value:
// Silly: why not an array instead of this.. a tuple is needed.. length must be exact 256..
// Don't know no other way to create a tuple with 256 elements...
var midiDataTuple = (z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z)
// use the above tuple in MIDIPacket
func midiSend(status: Int, val1: Int, val2 :Int)
{
var midipacket = MIDIPacket()
midipacket.timeStamp = 0
midipacket.length = 3
midipacket.data = midiDataTuple //<-=
midipacket.data.0 = UInt8(status)
midipacket.data.1 = UInt8(val1 )
midipacket.data.2 = UInt8(val2 )
var midipacketlist = MIDIPacketList(numPackets: 1, packet: midipacket)
MIDIReceived(midiSource, &midipacketlist)
}
//////////////////////////////////////////////////////////////
func noteOn(soundNr: Int, note: Int, velocity:Int)
{
let chan = midiChannelForSoundNr[soundNr]
midiSend((0x90 + chan), val1: note, val2: velocity)
notesPlaying[chan][note] = true
}
tested.
Swift 5 version, and probably the right way to encode midi packets.
First, esoteric pointer initialisations and memory rebounds are not needed to construct a MidiPacketList. Simply create your list the straight way and fill it.
This code pack midi events objects into a MidiPacketList. It works only with common musical events - See the Midi Protocol Specifications to deal with all types of events like sysex messages.
In most cases, only one packet is needed since the data size limit is 65536 bytes, which is largely enough for everything but sysex.
Send a noteOn for all notes in height octaves would need 1 status byte + 96 * 2 bytes for note number and velocity. 193 bytes.
The encoding in this example is quite performant
no function calls in the array init
no multiple calls to MIDIPacketListAdd
takes the running status in account to make messages as compact as possible.
To take advantage of the running status, it is best to sort midi events by types. So all notes on are grouped first, and then controls.
public static func packEvents(_ events: [MidiEvent]) throws -> MIDIPacketList? {
let numberOfEvents: UInt32 = UInt32(events.count)
guard numberOfEvents > 0 else { return nil }
var dataSize: Int = 0
// We could preflight the events list to only allocate the needed size, but the overhead is not worth it, since majority of musical events will be 3 bytes long
let bytes = [UInt8].init(unsafeUninitializedCapacity: 3 * Int(numberOfEvents)) { (pointer, count) in
// The number of data bytes in the message
var numBytes = 0
// The status byte of the last event
// According to MIDI protocol running status, we don't have to repeat the status if
// type and channels are equal ( status byte equals )
var runningStatus: UInt8 = 0
for event in events {
let status: UInt8 = (event.type.rawValue & 0xF0) | (event.channel & 0x0F)
// Encode status if needed
if status != runningStatus {
runningStatus = status
pointer[numBytes] = status
numBytes += 1
}
// Encode values
if event.numberOfDataBytes > 0 {
pointer[numBytes] = event.value1
numBytes += 1
}
if event.numberOfDataBytes > 1 {
pointer[numBytes] = event.value2
numBytes += 1
}
}
dataSize = numBytes
count = numBytes
}
var outPackets = MIDIPacketList()
var writePacketPtr = MIDIPacketListInit(&outPackets)
MIDIPacketListAdd(&outPackets, Int(14 + dataSize), writePacketPtr, 0, dataSize, bytes)
return outPackets
}
Here is the MidiEvent class used in the example.
public enum MidiEventType: UInt8 {
case noteOff = 0x80
case noteOn = 0x90
case polyAfterTouch = 0xA0
case control = 0xB0
case programChange = 0xC0
case afterTouch = 0xD0
case pitchBend = 0xE0
case clock = 0xF0
// The data length that follows the (Type|Channel) byte
public var dataLength: UInt8 {
switch self {
case .noteOff, .noteOn, .pitchBend, .control, .polyAfterTouch:
return 2
case .afterTouch, .programChange:
return 1
case .clock:
return 0
}
}
}
public struct MidiEvent: CustomStringConvertible {
public let type: MidiEventType
public let timestamp: UInt64
public let channel: UInt8
public let value1: UInt8
public let value2: UInt8
public var numberOfDataBytes: UInt8
// The mask to apply to data[0] to get type and channel
static let channelMask: UInt8 = 0x0F
static let typeMask: UInt8 = 0xF0
public init(type: MidiEventType, timestamp: UInt64 = 0, channel: UInt8, value1: UInt8, value2: UInt8 = 0) {
self.type = type
self.timestamp = timestamp
self.channel = channel
self.value1 = value1
self.value2 = value2
self.numberOfDataBytes = type.dataLength
}
}
Note that MidiPacketList this is deprecated since MacOS 11 and MidiEventList should be preferred to be compatible with midi protocol 2.0. The principle is the same, but alignment is 4 bytes.