Skip to content

Commit

Permalink
feat: add progress view
Browse files Browse the repository at this point in the history
  • Loading branch information
zhangyufei49 committed Dec 27, 2024
1 parent a409e4c commit 03bd3c4
Show file tree
Hide file tree
Showing 8 changed files with 304 additions and 4 deletions.
88 changes: 88 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Created by https://www.toptal.com/developers/gitignore/api/swift
# Edit at https://www.toptal.com/developers/gitignore?templates=swift

### Swift ###
# Xcode
#
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore

## User settings
xcuserdata/

## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
*.xcscmblueprint
*.xccheckout

## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
build/
DerivedData/
*.moved-aside
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3

## Obj-C/Swift specific
*.hmap

## App packaging
*.ipa
*.dSYM.zip
*.dSYM

## Playgrounds
timeline.xctimeline
playground.xcworkspace

# Swift Package Manager
# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
# Packages/
# Package.pins
# Package.resolved
# *.xcodeproj
# Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata
# hence it is not needed unless you have added a package configuration file to your project
# .swiftpm

.build/

# CocoaPods
# We recommend against adding the Pods directory to your .gitignore. However
# you should judge for yourself, the pros and cons are mentioned at:
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
# Pods/
# Add this line if you want to avoid checking in source code from the Xcode workspace
# *.xcworkspace

# Carthage
# Add this line if you want to avoid checking in source code from Carthage dependencies.
# Carthage/Checkouts

Carthage/Build/

# Accio dependency management
Dependencies/
.accio/

# fastlane
# It is recommended to not store the screenshots in the git repo.
# Instead, use fastlane to re-generate the screenshots whenever they are needed.
# For more information about the recommended setup visit:
# https://docs.fastlane.tools/best-practices/source-control/#source-control

fastlane/report.xml
fastlane/Preview.html
fastlane/screenshots/**/*.png
fastlane/test_output

# Code Injection
# After new code Injection tools there's a generated folder /iOSInjectionProject
# https://github.com/johnno1962/injectionforxcode

iOSInjectionProject/

# End of https://www.toptal.com/developers/gitignore/api/swift
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# playmid

A command line tool for MacOS which uses the system's built-in sound font assets to play **.mid** file.

![screenshot.jpg](screenshot.jpg)
36 changes: 36 additions & 0 deletions playmid.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
objectVersion = 77;
objects = {

/* Begin PBXBuildFile section */
0E80F2402D1E75BB0071F001 /* Progress in Frameworks */ = {isa = PBXBuildFile; productRef = 0E80F23F2D1E75BB0071F001 /* Progress */; };
/* End PBXBuildFile section */

/* Begin PBXCopyFilesBuildPhase section */
0E80F2322D1E75090071F001 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
Expand Down Expand Up @@ -35,6 +39,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
0E80F2402D1E75BB0071F001 /* Progress in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -77,6 +82,7 @@
);
name = playmid;
packageProductDependencies = (
0E80F23F2D1E75BB0071F001 /* Progress */,
);
productName = playmid;
productReference = 0E80F2342D1E75090071F001 /* playmid */;
Expand Down Expand Up @@ -106,6 +112,9 @@
);
mainGroup = 0E80F22B2D1E75090071F001;
minimizedProjectReferenceProxies = 1;
packageReferences = (
0E80F23E2D1E75BB0071F001 /* XCRemoteSwiftPackageReference "Progress.swift" */,
);
preferredProjectObjectVersion = 77;
productRefGroup = 0E80F2352D1E75090071F001 /* Products */;
projectDirPath = "";
Expand Down Expand Up @@ -248,7 +257,11 @@
0E80F23C2D1E75090071F001 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = "";
MACOSX_DEPLOYMENT_TARGET = 13.5;
PRODUCT_BUNDLE_IDENTIFIER = fun.padao.playmid;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
};
Expand All @@ -257,7 +270,11 @@
0E80F23D2D1E75090071F001 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = "";
MACOSX_DEPLOYMENT_TARGET = 13.5;
PRODUCT_BUNDLE_IDENTIFIER = fun.padao.playmid;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
};
Expand Down Expand Up @@ -285,6 +302,25 @@
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */

/* Begin XCRemoteSwiftPackageReference section */
0E80F23E2D1E75BB0071F001 /* XCRemoteSwiftPackageReference "Progress.swift" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/jkandzi/Progress.swift.git";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 0.4.0;
};
};
/* End XCRemoteSwiftPackageReference section */

/* Begin XCSwiftPackageProductDependency section */
0E80F23F2D1E75BB0071F001 /* Progress */ = {
isa = XCSwiftPackageProductDependency;
package = 0E80F23E2D1E75BB0071F001 /* XCRemoteSwiftPackageReference "Progress.swift" */;
productName = Progress;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = 0E80F22C2D1E75090071F001 /* Project object */;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"originHash" : "ce60120d05e30c0299b79ea3b9730d3ccaf4f1d74426ac8b92d14602a0160097",
"pins" : [
{
"identity" : "progress.swift",
"kind" : "remoteSourceControl",
"location" : "https://github.com/jkandzi/Progress.swift.git",
"state" : {
"revision" : "fed6598735d7982058690acf8f52a0a5fdaeb3e0",
"version" : "0.4.0"
}
}
],
"version" : 3
}
79 changes: 79 additions & 0 deletions playmid.xcodeproj/xcshareddata/xcschemes/playmid.xcscheme
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1620"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
buildArchitectures = "Automatic">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0E80F2332D1E75090071F001"
BuildableName = "playmid"
BlueprintName = "playmid"
ReferencedContainer = "container:playmid.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES"
viewDebuggingEnabled = "No">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0E80F2332D1E75090071F001"
BuildableName = "playmid"
BlueprintName = "playmid"
ReferencedContainer = "container:playmid.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0E80F2332D1E75090071F001"
BuildableName = "playmid"
BlueprintName = "playmid"
ReferencedContainer = "container:playmid.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,13 @@
<integer>0</integer>
</dict>
</dict>
<key>SuppressBuildableAutocreation</key>
<dict>
<key>0E80F2332D1E75090071F001</key>
<dict>
<key>primary</key>
<true/>
</dict>
</dict>
</dict>
</plist>
77 changes: 73 additions & 4 deletions playmid/main.swift
Original file line number Diff line number Diff line change
@@ -1,11 +1,80 @@
//
// main.swift
// playmid
// playmid.swift
// 使用 mac 自带的音色播放一个 mid 文件
// play .mid file with the system sound font resources of MacOS
//
// Created by 张宇飞 on 2024/12/27.
// Created by 张宇飞 on 2024/12/16.
//

import AVFoundation
import Foundation
import Progress

print("Hello, World!")
private func formatTime(_ seconds: TimeInterval) -> String {
let formatter = DateComponentsFormatter()
formatter.allowedUnits = [.minute, .second]
formatter.unitsStyle = .positional
formatter.zeroFormattingBehavior = .pad

let formattedString = formatter.string(from: seconds) ?? "00:00"
let milliseconds = Int((seconds.truncatingRemainder(dividingBy: 1)) * 1000)

return "\(formattedString).\(String(format: "%03d", milliseconds))"
}

private func timeToTicks(_ secs: TimeInterval) -> Int {
let ms = Int((secs.truncatingRemainder(dividingBy: 1)) * 1000)
let s = Int(secs.rounded(.towardZero))
return s * 1000 + ms
}

private func parseArgs() -> URL {
let args = CommandLine.arguments
if args.count != 2 {
let p = URL(fileURLWithPath: args[0]).lastPathComponent
print("Usage: \(p) <mid file path>")
exit(-1)
}

return URL(fileURLWithPath: args[1])
}

private struct ProgressPlayerCursor: ProgressElementType {
let player: AVMIDIPlayer

init(player: AVMIDIPlayer) {
self.player = player
}

public func value(_: ProgressBar) -> String {
return formatTime(player.currentPosition)
}
}

private func main() {
if let player = try? AVMIDIPlayer(contentsOf: parseArgs(), soundBankURL: nil) {
var running = true
player.play {
running = false
}

let totalTicks = timeToTicks(player.duration)
let duration = formatTime(player.duration)
var bar = ProgressBar(
count: totalTicks,
configuration: [
ProgressPlayerCursor(player: player),
ProgressBarLine(barLength: 60),
ProgressString(string: duration),
])

while running {
let ticks = timeToTicks(player.currentPosition)
bar.setValue(ticks)
usleep(500_000)
}
bar.setValue(totalTicks)
}
}

main()
Binary file added screenshot.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 03bd3c4

Please sign in to comment.