「Repete」(旧「語学学習支援プレイヤー」)をアップデートしました(ver 2.4.3)

iPhone/iPadアプリ「Repete」(レペテ)(旧「語学学習支援プレイヤー」)をアップデートしました。(ver 2.4.2 –> ver 2.4.3)

「Repete」(「語学学習支援プレイヤー」)は、語学学習の手助けをするオーディオプレイヤーです。ファイルの無音部分を分析し、流れる言葉が一区切りしたところで、あいだをおいて再生します
リピーティングに便利なオーディオプレイヤーです。

変更点

• ノンストップ再生時の音質を改善しました
ノンストップ再生時に、再生速度が1以外の場合、エコーがかかったような声になっていたのを修正しました。
• 録音機能使用開始時のアニメーションのちらつきを修正しました
• 待ち時間の下限を0.1秒としました
待ち時間が0秒の際に繰り返しを行うと、アイテム終端に達したのちアイテム始端に再生箇所を移動する処理が反応しきれないことがあり、再生が止まってしまう不具合がありました。
この問題に対処するために、待ち時間の下限を0.1秒としました。

よろしくお願いします。

「Repete」(旧「語学学習支援プレイヤー」)をアップデートしました(ver 2.4.2)

iPhone/iPadアプリ「Repete」(レペテ)(旧「語学学習支援プレイヤー」)をアップデートしました。(ver 2.4.1 –> ver 2.4.2)

「Repete」(「語学学習支援プレイヤー」)は、語学学習の手助けをするオーディオプレイヤーです。ファイルの無音部分を分析し、流れる言葉が一区切りしたところで、あいだをおいて再生します
リピーティングに便利なオーディオプレイヤーです。

変更点

• 前区切りへ戻るボタンの挙動を修正しました。
(3秒以下の区間を再生したあとの待ち時間に「前区切りへ戻るボタン」を押した場合、その区間の先頭から再生するように修正しました)

よろしくお願いします。

「Repete」(旧「語学学習支援プレイヤー」)をアップデートしました(ver 2.4.1)

iPhone/iPadアプリ「Repete」(レペテ)(旧「語学学習支援プレイヤー」)をアップデートしました。(ver 2.4 –> ver 2.4.1)

「Repete」(「語学学習支援プレイヤー」)は、語学学習の手助けをするオーディオプレイヤーです。ファイルの無音部分を分析し、流れる言葉が一区切りしたところで、あいだをおいて再生します
リピーティングに便利なオーディオプレイヤーです。

変更点

• 選曲画面で表示されるプレイリストのタイトルを適切なものに修正しました
(修正前はプレイリストがもつ最初の曲名が表示されていました)

よろしくお願いします。

2016年10月開発状況

前月に引き続きRepete Plusの開発中。
また、今月は懸案だったRepeteのiOS 10, Swift 3対応を行いました。

Repete PlusはRepeteの機能追加版です。
* オーディオファイルの区切り編集機能
* 曲送り・曲戻し
* 早送り・戻しでの秒数指定
* テキストメモ機能

が主な追加機能です。

10月末時点での開発中動画。


* ピンチ操作でオーディオデータ表示を拡大
* 不要な区切り点をタップ操作で削除
* チェックマークをタップして、再生/再生不要を切り替え


上旬

Repete PlusのUI部品の作成と配置、アプリアイコン作成を行いました。
なかなか定まらず、泥沼に。

テキスト編集ボタンとオーディオ編集ボタン

初期案

editor_fullscreen1008v1
ペンアイコンでテキスト編集ボタンを示しました。オーディオ編集ボタンをどのような図案にするか悩みました。オーディオ・ビデオ編集では「はさみ」を図案化したものなどがありますが、実際にやってもらう操作とそぐいません。Repete Plusでは「水滴」状の区切り点マークをタップやドラッグします。そこで、この「水滴」状マークを図案化してペンアイコンと雰囲気を揃えたものとしました。
白地に円形のボタンにしました。しかし、唐突感があって馴染んでいません。また、それぞれテキストに関連している、オーディオに関連しているというのがわかりづらいです。

中期案

editor_fullscreen1009v2
テキスト編集ボタンとオーディオ編集ボタンを再生関連ボタンに合わせて薄い浮き彫り風に変更。
また、対応しているエリアと線で結びました。
線で結ぶというアイデアはうまくいっていません。

決定案

editor_fullscreen1009v3
アイコンの図案の向きを変更して、対応エリアとの結びつきを強めました。
また、アイコンの位置を対応エリアに食いこませました。
再生関連ボタンの形状に準拠した角丸四角形に変更しました。

アプリアイコン

Repeteの後継であり、機能追加版であることを示すものにしようとの思い。

初期案

icon-old-120_white
ごちゃごちゃしすぎました。

シンプルに。
Repeteで用いていたふきだしをメインにしましょう。
ただ、ふきだしのアプリアイコンは、世にいろいろあります。Appleの「メッセージ」も緑にふきだし。
アイコンがならんでいるなかで、どれだっけと迷わずにえらべるものにする必要があります。

決定案

repete_plus_icon_120_white
周りに波のグラデーションを描きました。
発声を繰り返し繰り返し続けていくイメージを表現しています。

中旬

RepeteのiOS 10、Swift 3対応を行いました。
iOS 10からは、メディアライブラリへのアクセスの際に、アクセスを許容するかどうかの確認が入りました。
そこで「許可しない」を選ぶと、以後、選曲時にアプリが強制終了する不具合がありました。
Swift 2.3(移行時用の暫定バージョン)ではなく、Swift 3(Xcode 8でのスタンダードバージョン)に一挙に移行しようとして処理を進めましたが、ひどく時間がかかってしまいました。

外部ライブラリ(クラウドストレージ用のライブラリ)を対応させるのに時間がかかりました。
CocoaPodsを機能させるのに試行錯誤、ライブラリのAPIのバージョンが新たになったのでそれに対応させる、などなど。

また、表示崩れが生じている部分を修正。
iOS 10では、viewDidLoad時にconstraintのwidth,heightが反映されないので、そのため生じたレイアウト崩れを修正。
また、non-stopボタンの文字部分の描画をAutodesk Graphicが生成したコードで行なっていたが、ここでエラーが発生したので、UILabelに置き換えました。
UILabelに”Non-stop”と適切に描くためにNSAttributedStringを使用しました。

下旬

区切り情報、再生/非再生情報などを保存するために、Repete Plusでは、Realmを用いることにしました。
Realm: Create reactive mobile apps in a fraction of the time
外部ライブラリの使用では、ライブラリの導入段階でつまづき、サンプルがそのままでは動かないという事態が毎回のように発生していました。
なので、Realmを使うときもおそるおそる進めていったのですが、使ってみるととくにトラブルなくスムーズに導入、実行ができました。
ドキュメントも充実していて、なんといいますか、すごく心地よく作業を進めることができました。

Repeteでは、メディアライブラリアイテムのみ区切り情報をCoreDataを使って保存して、分析時間の短縮に用いていました。この機能はなければないで、(ちょっと分析に時間がかかるとはいえ)やっていけたのですが、今回のRepete Plusではそうもいきません。
Repete Plusでは、再生されたファイルを照合し、データベースにあれば、区切り情報、区間の再生/非再生情報、再生日時を呼び出す仕組みとしました。再生日時は、選曲画面の履歴タブに用います。

関連

2016年6月開発状況 – nackpan Blog
2016年7月開発状況 – nackpan Blog
2016年8月開発状況 – nackpan Blog
2016年9月開発状況 – nackpan Blog
2016年10月開発状況 – nackpan Blog
2016年11月開発状況 – nackpan Blog
2016年12月開発状況 – nackpan Blog
2017年1月開発状況 – nackpan Blog
2017年2月開発状況 – nackpan Blog

「Repete」(旧「語学学習支援プレイヤー」)をアップデートしました(ver 2.4)

iPhone/iPadアプリ「Repete」(レペテ)(旧「語学学習支援プレイヤー」)をアップデートしました。(ver 2.3.1 –> ver 2.4)

「Repete」(「語学学習支援プレイヤー」)は、語学学習の手助けをするオーディオプレイヤーです。ファイルの無音部分を分析し、流れる言葉が一区切りしたところで、あいだをおいて再生します
リピーティングに便利なオーディオプレイヤーです。

変更点

• iPhone 4sで、選曲後、アプリが強制終了する不具合を修正しました

• Non-stop再生ボタンの表示がおかしかったのを修正しました

• そのほか細かなバグを修正しました

よろしくお願いします。

「Repete」(旧「語学学習支援プレイヤー」)をアップデートしました(ver 2.3)

iPhone/iPadアプリ「Repete」(レペテ)(旧「語学学習支援プレイヤー」)をアップデートしました。(ver 2.2 –> ver 2.3)

「Repete」(「語学学習支援プレイヤー」)は、語学学習の手助けをするオーディオプレイヤーです。ファイルの無音部分を分析し、流れる言葉が一区切りしたところで、あいだをおいて再生します
リピーティングに便利なオーディオプレイヤーです。

変更点

• iOS 10で使用時、「選曲」ボタンを押したさいに強制終了する不具合を修正しました。

• このバージョンからiOS 9.3以降対応となります。


よろしくお願いします。

2016年9月開発状況

前月に引き続きRepete Plusの開発中。

Repete PlusはRepeteの機能追加版です。
* オーディオファイルの区切り編集機能
* 曲送り・曲戻し
* 早送り・戻しでの秒数指定
* 歌詞表示

が主な追加機能です。

前半

今月は、iOS 10、Xcode 8がリリースされました。
Xcode 8からは、推奨されるSwiftのバージョンが2系から3.0になりました。
今月前半は、「Repete」「Rendow」「Repete Plus」をiOS 10、Swift 3に対応させる処理を行いました。
Xcodeの自動コンバートでは対応しきれないCore Graphicコードの書き換え用にRubyで簡易コンバーターを作成しました。
CoreGraphicsコードをSwift 3.0に変換する – nackpan Blog

後半

「区切り点編集機能」のプレイヤーへの組み込みを行いました。

再生中、停止中、待ち中に
* 区切り点の移動
* 区間の使用・不使用チェック
を行ったとき、プレイヤーにその操作が適切に反映されるようにしました。

スクロール直後に軽くpanしたときに、意図せず区切り点の移動になってしまう症状が出ていたのを直しました。

テキスト表示機能の試作をおこないました。

関連

2016年6月開発状況 – nackpan Blog
2016年7月開発状況 – nackpan Blog
2016年8月開発状況 – nackpan Blog
2016年9月開発状況 – nackpan Blog
2016年10月開発状況 – nackpan Blog
2016年11月開発状況 – nackpan Blog
2016年12月開発状況 – nackpan Blog
2017年1月開発状況 – nackpan Blog
2017年2月開発状況 – nackpan Blog

CoreGraphicsコードをSwift 3.0に変換する

Xcode 8.0が登場しました。
旧プロジェクトをXcode 8.0で開くと、Swift 3.0(あるいはSwift 2.4)に変換するよう促すダイアログが出現しました。

CoreGraphicsコードをSwift 3.0への自動コンバートにかけたところ、変換されない部分が残りました。

        let pathRef = CGMutablePath()
        CGPathMoveToPoint(pathRef, nil, 20, 0)
        CGPathAddLineToPoint(pathRef, nil, 200, 0)
        CGPathAddCurveToPoint(pathRef, nil, 205.523, 0, 210, 4.435, 210, 10)
        CGPathAddLineToPoint(pathRef, nil, 210, 122)
        CGPathAddCurveToPoint(pathRef, nil, 210, 127.565, 205.523, 132, 200, 132)
        CGPathAddLineToPoint(pathRef, nil, 10, 132)
        CGPathAddCurveToPoint(pathRef, nil, 4.477, 132, -0, 127.565, -0, 122)
        CGPathAddLineToPoint(pathRef, nil, -0, 20)
        CGPathAddCurveToPoint(pathRef, nil, -0, 9.087, 9.081, 0, 20, 0)
        pathRef.closeSubpath()

変換後、このようなコードになったのですが最終的には

        let pathRef = CGMutablePath()
        pathRef.move(to: CGPoint(x: 20, y: 0))
        pathRef.addLine(to: CGPoint(x: 200, y: 0))
        pathRef.addCurve(to: CGPoint(x: 210, y: 10), control1: CGPoint(x: 205.523, y: 0), control2: CGPoint(x: 210, y: 4.435))
        pathRef.addLine(to: CGPoint(x: 210, y: 122))
        pathRef.addCurve(to: CGPoint(x: 200, y: 132), control1: CGPoint(x: 210, y: 127.565), control2: CGPoint(x: 205.523, y: 132))
        pathRef.addLine(to: CGPoint(x: 10, y: 132))
        pathRef.addCurve(to: CGPoint(x: -0, y: 122), control1: CGPoint(x: 4.477, y: 132), control2: CGPoint(x: -0, y: 127.565))
        pathRef.addLine(to: CGPoint(x: -0, y: 20))
        pathRef.addCurve(to: CGPoint(x: 20, y: 0), control1: CGPoint(x: -0, y: 9.087), control2: CGPoint(x: 9.081, y: 0))
        pathRef.closeSubpath()

と変換したい。

文字列の処理がやりやすいのはなにかしらと考えて、急遽Rubyを学ぶことにしました。


文字列操作とファイル操作の基本的なやりかたを知ったので、以下の変換プログラム converter.rbを書きました。
CGPathMoveToPoint(pathRef, nil, 20, 0)

pathRef.move(to: CGPoint(x: 20, y: 0))

CGPathAddLineToPoint(pathRef, nil, 200, 0)

pathRef.addLine(to: CGPoint(x: 200, y: 0))

CGPathAddCurveToPoint(pathRef, nil, 205.523, 0, 210, 4.435, 210, 10)

pathRef.addCurve(to: CGPoint(x: 210, y: 10), control1: CGPoint(x: 205.523, y: 0), control2: CGPoint(x: 210, y: 4.435))

と変換するものです。

converter.rb

class Converter

    def convert()
        loop do 
            print "Filename? "
            fileName = gets.chomp
            
            if fileName == ""
                break
            end
            
            # Backup
            from = fileName
            to = "_" + fileName + ".bak"
            copy(from, to)
            
            # Conversion
            array = []
            File.open(fileName) do |file|
                file.each_line do |line|
                    line = convertCoreGraphicsCode(line)
                    array.push(line)
                end
            end
                
            # Writing
            File.open(fileName, "w") do |file|
                file.puts(array)
                puts fileName + " 変換終了"
            end
        end
    end
    
    def copy(from, to)
        File.open(from) do |input|
            File.open(to, "w") do |output|
                output.write(input.read)
            end
        end
    end

    def convertCoreGraphicsCode(line)
        if line.include?("CGPathMoveToPoint")
            return convertMoveToPoint(line)
        elsif line.include?("CGPathAddLineToPoint") 
            return convertAddLineToPoint(line)
        elsif line.include?("CGPathAddCurveToPoint")
            return convertAddCurveToPoint(line)
        else
            return line
        end
    end
    
    # CGPathMoveToPoint(clipPath, nil, 240, 122)
    # to
    # clipPath.move(to: CGPoint(x: 240, y: 122))
    def convertMoveToPoint(line)
        # indentを取得
        index = line.index("CGPathMoveToPoint")
        indent = line[0, index]
        
        # path名を含むかたまりを取得("CGPathMoveToPoint(clipPath,")
        pathStr = line.match(/CGPathMoveToPoint\(\w+,/)
        
        # path名を取得("clipPath")
        pathName = pathStr[0].sub("CGPathMoveToPoint\(", "").chop
        # puts pathName
        
        # 数値
        figuresStr = line.sub(/CGPathMoveToPoint\(\w+, nil,/, "").chomp.chop.lstrip
        figuresStr = " " + figuresStr
        figures = figuresStr.split(",")
        # puts figures
        
        dstStr = "%s%s.move(to: CGPoint(x:%s, y:%s))" % [indent, pathName, figures[0], figures[1]]
        # puts dstStr
        return dstStr
    end
    
    
    # CGPathAddLineToPoint(clipPath, nil, 240, 122)
    # to
    # clipPath.addLine(to: CGPoint(x: 240, y: 122))
    def convertAddLineToPoint(line)
        # indentを取得
        index = line.index("CGPathAddLineToPoint")
        indent = line[0, index]
        
        # path名を含むかたまりを取得("CGPathAddLineToPoint(clipPath,")
        pathStr = line.match(/CGPathAddLineToPoint\(\w+,/)
        
        # path名を取得("clipPath")
        pathName = pathStr[0].sub("CGPathAddLineToPoint\(", "").chop
        # puts pathName
        
        # 数値
        figuresStr = line.sub(/CGPathAddLineToPoint\(\w+, nil,/, "").chomp.chop.lstrip
        figuresStr = " " + figuresStr
        figures = figuresStr.split(",")
        # puts figures

        dstStr = "%s%s.addLine(to: CGPoint(x:%s, y:%s))" % [indent, pathName, figures[0], figures[1]]
        # puts dstStr
        return dstStr
    end
    
    # CGPathAddCurveToPoint(pathRef2, nil, 4.477, 132, 0, 127.565, 0, 122)
    # to
    # pathRef2.addCurve(to: CGPoint(x: 0, y: 122), control1: CGPoint(x: 4.477, y: 132), control2: CGPoint(x: 0, y: 127.565))
    def convertAddCurveToPoint(line)

        # indentを取得
        index = line.index("CGPathAddCurveToPoint")
        indent = line[0, index]
        
        # path名を含むかたまりを取得("CGPathAddCurveToPoint(pathRef2,")
        pathStr = line.match(/CGPathAddCurveToPoint\(\w+,/)
        
        # path名を取得("pathRef2")
        pathName = pathStr[0].sub("CGPathAddCurveToPoint\(", "").chop
        # puts pathName
        
        # 数値を取得
        figuresStr = line.sub(/CGPathAddCurveToPoint\(\w+, nil,/, "").chomp.chop.lstrip
        figuresStr = " " + figuresStr
        figures = figuresStr.split(",")
        # puts figures
        
        dstStr = "%s%s.addCurve(to: CGPoint(x:%s, y:%s), control1: CGPoint(x:%s, y:%s), control2: CGPoint(x:%s, y:%s))" % [indent, pathName, figures[4], figures[5], figures[0], figures[1], figures[2], figures[3]]
        # puts dstStr
        return dstStr 
    end

end

converter = Converter.new
converter.convert()

変換したいswiftファイルがあるフォルダに、converter.rbをおき、Terminalでそのフォルダへ移動した後、

ruby converter.rb  

と入力するとプログラムが実行されます。
実行すると、

FileName?  

とたずねられるので、そこで変換したいファイル名を入力すると変換が行われます。
(このさい、”_元ファイル名.bak”というバックアップファイルも作成します。)
ファイル名を入力せずにreturnキーを押すと、プログラムは終了します。

関連

Autodesk Graphic(旧iDraw)はCore Graphicsのコードを生成できる – nackpan Blog