簡単!音源カットの裏技 + おまけ【うみぐりゃーずアドベントカレンダー 2025】

うみぐりゃーずアドベントカレンダー 2025 16 日目の記事です。

adventar.org



はじめに

こんにちは、UMIGURI 開発者の いののて です。最近は社会人をしていて仕事でコードを書いてます。前回が 3 年前なので、これだけ時間が経てば身分が変わるのも不思議ではないですね。

....

音源カットしてますか?(唐突)

...

ゲームの性質上、4 から 5 分程度の FULL 尺音源を 2 分半程度に収めると作譜しやすかったりプレイヤーの回転率が上がったりとなにかと都合がいいです。しかしそんな望み通りに 2 分半に調整されたバージョンが公開されている音源はゲーム音楽を除いてあまりないので我々で音源カットをする必要があります。

今回は UMIGURI 開発者おすすめの音源カット方法について紹介しようと思います。



用意するもの



STEP 1 - BPM を計測する

Margrete を使っていつものように音源ファイルなど設定した mgxc ファイルを準備します。

その mgxc ファイルを開いた状態でメニューの ツール > BPM 解析 をクリックします。

なるほど、BPM が 170 だということがわかりました。

注意: いくつか候補が出てくるので注意深く選択してください。また、BPM が変動していたりすると正しく計測できないため、別の方法で解析してください。



STEP 2 - Audacity でリズムトラックを作る

ここからは Audacity を使った作業です。

まず、なるべく正確に音源をカットしたいのでタイミング合わせ用のリズムトラックを作ります。

AudacityBPM でスナップできる機能がありはするのですが、微妙に不具合があるので今回は使いません。

音源を Audacity に読み込ませたところです。

メニューの ファイル > 開く...

ここで、メニューの トラック > 新規追加 > モノラルトラック をクリック。

元からある波形の下に何やら空白の領域、トラックが追加されました。

次に、リズムトラックを追加します。

さっき追加したトラックを選択した状態で、メニューの 生成 > リズムトラック をクリック。

調整画面が表示されるので、テンポ (BPM) に先程測定した BPM を設定します。小節数 は 120 ~ 200 程度に設定します。

小節数はリズムトラックが生成される長さなので、曲の尺に合わない場合は増やしたり減らしたりしてみてください。

これで空白のトラックがリズムトラックに生まれ変わりました🎉



STEP 3 - 頭出し

現状ではリズムトラックと音源の BPM は合っていますが、開始タイミングがズレている状態です。 ここではカットのしやすさのためにタイミングを合わせたいと思います。(譜面オフセット調整を正確にするためでもあります)

まず、小節が始まりそうな目立つアタック (音の立ち上がり) 部分を探します。

見つけたら音源トラック上部の若干色が濃いバーを掴んで、音源とリズムトラックのアタックタイミングが重なるように調整します。リズムトラックに並ぶ波形のうち振れ幅が大きいものが小節の頭なので、それを目印に合わせると良いでしょう。

💡 TIPS: Ctrl キー + マウスホイールで拡大縮小ができます。

移動したあとで音源トラックの先頭に空白の領域が生まれていた場合は、マウスでその領域を選択し、メニューの 生成 > 無音... > 生成 ボタンで間を埋めます。

逆にこのように頭が埋まっていた場合は右に 1 小節分ずらして、頭が途切れないように調整します。(生まれた空白は上の方法で埋めておきます)



STEP 4 - カットの開始点と終了点にラベルを付ける

カットする箇所にラベルを付けることで、削除するときのタイミング合わせがスムーズになります。

まず、カット箇所を見つけたら波形をクリックしてカーソルをセットします。リズムトラックのアタック部分を活用すると厳密なタイミング合わせができます。カーソルがセットできたら黒い線がクリックした部分に移動してくれます。

カーソル位置にラベルを貼ります。メニューの 編集 > ラベル > 選択範囲にラベル付け で貼り付けることができます。

名前の設定ができるのでわかりやすい名前を付けます。

begin の名前で貼り付けてみた

これでカットの開始点のラベルを付けることができました。同様にカット終了点も付けます。また、複数カット範囲がある場合はこれを繰り返します。



STEP 5 - 実際にカットする

音源トラック、リズムトラック、ラベルトラックを跨ぐように、カット開始点ラベルからカット終了点ラベルまでを範囲選択します。

💡 TIPS: ラベルトラックも含めないと、カット範囲が複数ある場合は削除した分のタイミングが調整されません。

ラベル位置付近にマウスを運ぶとラベルのタイミングに吸い付いて自動でタイミング合わせしてくれるので、これを活用すると正確です。

範囲選択したところで Delete キーを押すことでカットできます。



STEP 6 - 音源を出力する

出力した音源にリズムトラックが入り込んでしまうので、先にリズムトラック左端にある小さな x をクリックして削除しておきます。

削除したら、メニューの ファイル > オーディオをエクスポート > コンピューターにエクスポート で音源を出力できます。(エクスポート方法は Audacity のバージョンによって違う場合があります。)



STEP 7 - 完成!!!!!

完成しました。忘れずに mgxc の音源ファイルの指定もカット済み音源に変えておきましょう。

また、今回頭出しをしたことで譜面のオフセットを調整する必要がなくなりました。そのため、譜面情報編集画面の 音源再生遅延 を 0 に設定するとタイミングピッタリになると思います。



上級編

Audacity は複数のトラックを持てるので、カット箇所のぶつ切り感が気になる場合は滑らかにするためにトラックを並べてクロスフェードさせることもできます。

エフェクト > クロスフェード




関係のないおまけ

虹色ロング

わあきれい

TODO: よしなに不動 SLIDE のレギュ違反回避

絵文字

discord.gg



おわりに

最後にこの言葉で締めようと思います。


欧米風の唐揚げ、カラエイジ (karaage)


おわり

HSP3だけでCOMインターフェースを実装してみる

COM のオブジェクトはクラスなど使わなくても、QueryInterface などの各メソッドへのアドレスを列挙した配列 (仮想関数テーブル) と、それへのアドレスを適切にメモリに配置するだけで成り立ちます。

HSP3 にはクラスや構造体を実装する機能はありませんが、コールバック用の関数アドレスを生成するプラグインとメモリ操作命令があります。これらを活用することで HSP3 でも COM インターフェースの実装ができます。

その実証のためにエクスプローラー ビューである IExplorerBrowser のコールバック インターフェース IExplorerBrowserEvents を実装してみました。IExplorerBrowser はビューが生成されたりナビゲーションが発生した場合に IExplorerBrowserEvents の対応するメソッドを呼び出します。

今回のサンプルではフォルダーなどをクリックしてナビゲーションを発生させるとタイトルバーに情報が表示されるようにしています。それとなぜかフォルダーをダブルクリックすると別窓が開いてしまうのでコンテキスト メニューから 2 番目の 開く コマンドを選択する必要があります。

コード

※hscallbk が必要

#include "hscallbk.as"

#define NULL 0
#define S_OK 0
#define E_INVALIDARG 0x80070057
#define E_NOINTERFACE 0x80004002

#define CLSCTX_INPROC_SERVER 1

#define FVM_AUTO -1
#define FVM_FIRST 1
#define FVM_ICON 1
#define FVM_SMALLICON 2
#define FVM_LIST 3
#define FVM_DETAILS 4
#define FVM_THUMBNAIL 5
#define FVM_TILE 6
#define FVM_THUMBSTRIP 7
#define FVM_CONTENT 8
#define FVM_LAST 8

#define FWF_FULLROWSELECT 0x200000

#define SBSP_DEFBROWSER         0x0000
#define SBSP_SAMEBROWSER        0x0001
#define SBSP_NEWBROWSER         0x0002
#define SBSP_DEFMODE            0x0000
#define SBSP_OPENMODE           0x0010
#define SBSP_EXPLOREMODE        0x0020
#define SBSP_HELPMODE           0x0040
#define SBSP_NOTRANSFERHIST     0x0080
#define SBSP_ABSOLUTE           0x0000
#define SBSP_RELATIVE           0x1000
#define SBSP_PARENT             0x2000
#define SBSP_NAVIGATEBACK       0x4000
#define SBSP_NAVIGATEFORWARD    0x8000

#define SHGFI_DISPLAYNAME 0x000000200
#define SHGFI_PIDL 0x000000008

#uselib "msvcrt"
#cfunc malloc "malloc" int
#func free "free" int
#cfunc memcmp "memcmp" int, int, int

#uselib "kernel32"
#func InterlockedIncrement "InterlockedIncrement" int
#func InterlockedDecrement "InterlockedDecrement" int

#uselib "shell32"
#func SHGetFileInfoA "SHGetFileInfoA" int, int, int, int, int
#func SHParseDisplayName "SHParseDisplayName" wptr, int, int, int, int

#uselib "ole32"
#func CLSIDFromString "CLSIDFromString" wptr, int
#func CoCreateInstance "CoCreateInstance" int, int, int, int, int
#func CoTaskMemFree "CoTaskMemFree" int

// IExplorerBrowserEvents 用の仮想関数テーブルを作る
#uselib ""
#func IExplorerBrowserEvents_QueryInterface "" int, int, int
setcallbk CExplorerBrowserEvents_QueryInterface, IExplorerBrowserEvents_QueryInterface, *FnCExplorerBrowserEvents_QueryInterface
#func IExplorerBrowserEvents_AddRef "" int
setcallbk CExplorerBrowserEvents_AddRef, IExplorerBrowserEvents_AddRef, *FnCExplorerBrowserEvents_AddRef
#func IExplorerBrowserEvents_Release "" int
setcallbk CExplorerBrowserEvents_Release, IExplorerBrowserEvents_Release, *FnCExplorerBrowserEvents_Release
#func IExplorerBrowserEvents_OnNavigationPending "" int, int
setcallbk CExplorerBrowserEvents_OnNavigationPending, IExplorerBrowserEvents_OnNavigationPending, *FnCExplorerBrowserEvents_OnNavigationPending
#func IExplorerBrowserEvents_OnViewCreated "" int, int
setcallbk CExplorerBrowserEvents_OnViewCreated, IExplorerBrowserEvents_OnViewCreated, *FnCExplorerBrowserEvents_OnViewCreated
#func IExplorerBrowserEvents_OnNavigationComplete "" int, int
setcallbk CExplorerBrowserEvents_OnNavigationComplete, IExplorerBrowserEvents_OnNavigationComplete, *FnCExplorerBrowserEvents_OnNavigationComplete
#func IExplorerBrowserEvents_OnNavigationFailed "" int, int
setcallbk CExplorerBrowserEvents_OnNavigationFailed, IExplorerBrowserEvents_OnNavigationFailed, *FnCExplorerBrowserEvents_OnNavigationFailed

dim CExplorerBrowserEventsVtbl, 7
CExplorerBrowserEventsVtbl(0) = varptr(CExplorerBrowserEvents_QueryInterface)
CExplorerBrowserEventsVtbl(1) = varptr(CExplorerBrowserEvents_AddRef)
CExplorerBrowserEventsVtbl(2) = varptr(CExplorerBrowserEvents_Release)
CExplorerBrowserEventsVtbl(3) = varptr(CExplorerBrowserEvents_OnNavigationPending)
CExplorerBrowserEventsVtbl(4) = varptr(CExplorerBrowserEvents_OnViewCreated)
CExplorerBrowserEventsVtbl(5) = varptr(CExplorerBrowserEvents_OnNavigationComplete)
CExplorerBrowserEventsVtbl(6) = varptr(CExplorerBrowserEvents_OnNavigationFailed)

/*
CExplorerBrowserEvents メモリ レイアウト

0 4 void* CExplorerBrowserEventsVtbl
4 4 ULONG m_refCount
8 4 DWORD m_cookie
*/
#define SizeOfCExplorerBrowserEvents 12
#define CExplorerBrowserEvents_Vtbl 0
#define CExplorerBrowserEvents_RefCount 4
#define CExplorerBrowserEvents_Cookie 8

#module
// オブジェクトとメソッド番号からメソッドの関数アドレスを取得する便利関数
#defcfunc getMethodAddr int pObj, int index
    dupptr _pObjVtbl, pObj, 4, 4
    dupptr _pMethod, _pObjVtbl + 4 * index, 4, 4
    return _pMethod
#global

// 文字列から GUID 構造体に変換
dim CLSID_ExplorerBrowser, 4
CLSIDFromString "{71f96385-ddd6-48d3-a0c1-ae06e8b055fb}", varptr(CLSID_ExplorerBrowser)

dim IID_IUnknown, 4
CLSIDFromString "{00000000-0000-0000-C000-000000000046}", varptr(IID_IUnknown)

dim IID_IExplorerBrowser, 4
CLSIDFromString "{dfd3b6b5-c10c-4be9-85f6-a66969f402f6}", varptr(IID_IExplorerBrowser)

dim IID_IExplorerBrowserEvents, 4
CLSIDFromString "{361bbdc7-e6ee-4e13-be58-58e2240c810f}", varptr(IID_IExplorerBrowserEvents)

// エクスプローラー ブラウザーを作成
pExplorerBrowser = 0
hr = CoCreateInstance(varptr(CLSID_ExplorerBrowser), NULL, CLSCTX_INPROC_SERVER, varptr(IID_IExplorerBrowser), varptr(pExplorerBrowser))
if (pExplorerBrowser == 0) {
    mes "pExplorerBrowser is null"
    stop
}

// ブラウザー初期化
rect = 0, 26, ginfo_winx, ginfo_winy
fs = FVM_DETAILS, FWF_FULLROWSELECT
prms = pExplorerBrowser, hwnd, varptr(rect), varptr(fs)
hr = callfunc(prms, getMethodAddr(pExplorerBrowser, 3) /* IExplorerBrowser_Initialize */, length(prms))

// コールバック登録
pExplorerBrowserEvents = NewCExplorerBrowserEvents()
prms = pExplorerBrowser, pExplorerBrowserEvents, pExplorerBrowserEvents + CExplorerBrowserEvents_Cookie
hr = callfunc(prms, getMethodAddr(pExplorerBrowser, 9) /* IExplorerBrowser_Advise */, length(prms))

// フォルダーへ移動
pIdList = 0
SHParseDisplayName "C:\\", NULL, varptr(pIdList), 0, NULL // ファイル パスから IDLIST へ変換
prms = pExplorerBrowser, pIdList, SBSP_DEFBROWSER
hr = callfunc(prms, getMethodAddr(pExplorerBrowser, 13) /* IExplorerBrowser_BrowseToIDList */, length(prms))
CoTaskMemFree pIdList
pIdList = 0

objsize 50, 26
pos 0, 0: button gosub "戻る", *goBack
pos 50, 0: button gosub "進む", *goForward
pos 100, 0: button gosub "上へ", *goParent

onexit *exit
stop

*goBack
    prms = pExplorerBrowser, NULL, SBSP_NAVIGATEBACK
    hr = callfunc(prms, getMethodAddr(pExplorerBrowser, 13) /* IExplorerBrowser_BrowseToIDList */, length(prms))
    return
    
*goForward
    prms = pExplorerBrowser, NULL, SBSP_NAVIGATEFORWARD
    hr = callfunc(prms, getMethodAddr(pExplorerBrowser, 13) /* IExplorerBrowser_BrowseToIDList */, length(prms))
    return
    
*goParent
    prms = pExplorerBrowser, NULL, SBSP_PARENT
    hr = callfunc(prms, getMethodAddr(pExplorerBrowser, 13) /* IExplorerBrowser_BrowseToIDList */, length(prms))
    return
    
*exit
    if (pExplorerBrowser) {
        prms = pExplorerBrowser
        hr = callfunc(prms, getMethodAddr(pExplorerBrowser, 4) /* IExplorerBrowser_Destroy */, length(prms))
    
        prms = pExplorerBrowser
        hr = callfunc(prms, getMethodAddr(pExplorerBrowser, 2) /* IExplorerBrowser_Release */, length(prms))
        
        pExplorerBrowser = 0
    }
    end

// -----------------------------------------
// CExplorerBrowserEvents メンバー関数の実装
// -----------------------------------------
*FnCExplorerBrowserEvents_QueryInterface
    // params: This, riid, ppvObject
    if (callbkarg(2) == 0) { // ppvObject が NULL
        return E_INVALIDARG
    }
    
    dupptr pvObject, callbkarg(2), 4, 4
    pvObject = 0

    // IID_IUnknown か IID_IExplorerBrowserEvents ならインターフェース変換可能
    if (memcmp(varptr(IID_IUnknown), callbkarg(1), 4) == 0 || memcmp(varptr(IID_IExplorerBrowserEvents), callbkarg(1), 4) == 0) {
        pvObject = callbkarg(0)
        prms = callbkarg(0)
        hr = callfunc(prms, getMethodAddr(callbkarg(0), 1) /* IExplorerBrowserEvents_AddRef */, length(prms))
        return S_OK
    }
    return E_NOINTERFACE
    
*FnCExplorerBrowserEvents_AddRef
    // params: This
    return InterlockedIncrement(callbkarg(0) + CExplorerBrowserEvents_RefCount)
    
*FnCExplorerBrowserEvents_Release
    // params: This
    ref = InterlockedDecrement(callbkarg(0) + CExplorerBrowserEvents_RefCount)
    if (ret == 0) {
        // CExplorerBrowserEvents クラスを破棄
        free callbkarg(0)
        return 0
    }
    return ref
    
*FnCExplorerBrowserEvents_OnNavigationPending
    // params: This, pidlFolder

    title "ナビゲーション中..."
    return S_OK
    
*FnCExplorerBrowserEvents_OnViewCreated
    // params: This, psv
    return S_OK
    
*FnCExplorerBrowserEvents_OnNavigationComplete
    // params: This, pidlFolder

    // 現在のフォルダー名をタイトルバーに表示させてみる
    sdim fi, 360 // SHFILEINFOA
    if (SHGetFileInfoA(callbkarg(1), 0, varptr(fi), 360, SHGFI_DISPLAYNAME | SHGFI_PIDL)) {
        sdim szDisplayName
        getstr szDisplayName, fi, 12, '0', 260
        title "成功: " + szDisplayName
    }
    return S_OK
    
*FnCExplorerBrowserEvents_OnNavigationFailed
    // params: This, pidlFolder
    
    title "失敗"
    return S_OK

#defcfunc NewCExplorerBrowserEvents
    // CExplorerBrowserEvents クラスを構築
    pObj = malloc(SizeOfCExplorerBrowserEvents)
    dupptr _obj, pObj, SizeOfCExplorerBrowserEvents, 4
    _obj(0) = varptr(CExplorerBrowserEventsVtbl) // CExplorerBrowserEventsVtbl
    _obj(1) = 1 // m_refCount
    _obj(2) = 0 // m_cookie
return pObj

文章に使われている文字抽出ツール

サブセット フォントを作るときとかに使えると思います。
処理はブラウザ内で完結し、外部には送信されません。




ノーツ描画の仕様【うみぐりゃーずアドベントカレンダー 2022】

うみぐりゃーずアドベントカレンダー 2022 3 日目の記事です。

adventar.org



はじめに

こんにちは、UMIGURI の開発者の いののて です。趣味でソフトウェアを開発したりゲーセンで某スライダーを擦る音ゲーをしたりしています。弾幕 STG音ゲーもぼちぼちしてます。ところで聖女アンナちゃん、可愛いですよね。もちろん今開催中のグッズキャンペーンで新規立ち絵入手するつもりです。アンナちゃんが貰える期間の最終日が 1 月 11 日、僕の誕生日は 1 月 15 日。近い。まるで誕生日プレゼントのようですね。

すこだ......

今回、嬉しいことに主催の ひとみとせ さんに うみぐりゃーずアドベントカレンダー 書きませんか!?と誘われて参加することになりました。

アドベントカレンダーは今まで専ら読むだけだったのですがこうして初めての記事、ということで結構緊張しますね。



ノーツ描画の仕様

画像がないと寂しいので適当にパワポで作成した画像

設定したテーマ 開発者として ということで、この記事では本家や UMIGURI のノーツ描画の仕様について 3 つ解説します。ギミックや AIR-TRACE などで装飾を施す際などに参考になれば幸いです。

地面ノーツの描画順

地面ノーツ (TAP、ExTAP、SLIDE、HOLD、FLICK、DAMAGE) はその種類とフィールド上の奥行き方向の位置によって描画順が決まります。(最背面から順に描画されます。)

幅が狭いノーツが上になり、同じ幅同士は奥のノーツが上になる

注意: UMIGURI は奥行き順ではなく時間順で描画するようになっているので (不具合です) 追い越しノーツの描画順が設計と異なる挙動になっています。また、本来は SLIDE の中継点と終点ノーツにもこれらの規則が適用されるのですが UMIGURI は無視して始点の描画順に依存して描画します。



AIR 系ノーツの描画順

AIR 系ノーツ (AIRAIR-HOLD、AIR-SLIDE、AIR-CRUSH、AIR-TRACE) は一部を除いて、その種類とフィールド上の奥行き方向の位置によって描画順が決まります。(最背面から順に描画されます。)

譜面に装飾を施しても意図した見た目にならない場合は描画順を考慮すると解決できることがあります。

それぞれのノーツに AIR-TRACE を重ねたときの様子

AIR 系ノーツの描画順について
AIR 系ノーツは立体的なオブジェクトなので、現実世界のように視点から見て手前に位置する物体は手前に、奥に位置する物体は奥になるよう描画したいですよね (開発者目線)。それを実現するためにゲームなどのリアルタイムレンダリング*1 用途の 3DCG では Z バッファ法 という技術があります。

この技術を使えば描画順を気にせず奥行きを考慮した描画ができるのですが、万能ではなく、テクスチャ (オブジェクトの表面に貼り付ける画像) に半透明で後ろが透けて見える部分があるとうまくいかないことがあります。

UMIGURI (や本家) では、AIR-CRUSH の箱の枠や始点の箱の紫の部分、AIR-ACTION は完全不透明なためこの技術を使って順番を気にせずに描画することができます。しかしそれ以外の AIR 系ノーツはテクスチャに半透明要素があるため、それらに描画順を設定し前後関係が擬似的に極力自然に見えるよう描画しています。

不透明と半透明
半透明オブジェクトを不透明オブジェクトと同じように描画するとおかしな結果になる

詳しい解説: ゲームなどのリアルタイムレンダリング用途では奥行きを処理するために高速な Z バッファ法 が用いられます。この手法を簡単に説明すると描画したいオブジェクトが手前のオブジェクトによって隠れていた場合は描画せず、隠れていなかった場合は描画する仕組みになっています。しかしこれには罠があり、手前のオブジェクトが不透明の場合は正常な結果が得られますが、半透明だった場合は後ろが透けているのにもかかわらず隠れた部分が描画されないためおかしな結果になます。そのため 3DCG を扱うゲームなどのソフトウェアでは不透明オブジェクトを先に描画し、次に半透明オブジェクトをそれらに描画順を設定して、物体同士の奥行き判定を不透明オブジェクトに限定しながら描画する実装になっていることが多いです。



ノーツが中央判定タイミングを超えたときの挙動

ノーツが中央判定タイミング (ガイド音が鳴るタイミング) を超えたとき、流れる速度が等倍になります。

例えば -1.0 倍速にして手前からノーツが流れるようにした場合は、判定線に重なった瞬間に反射したような挙動になります。

ロングノーツの背景部分は判定線跨いだとき、これを境に手前側は等速で流したときと同じ形状になります。

-1.0 倍速設定の SLIDE。判定線で反射したような見た目になる。手動プレイかつ放置しないと見られない貴重な光景
0.25 倍速設定の AIR-SLIDE。判定線から手前の部分は等速になるので吸われているような見た目になる
HOLD は判定線で切れて AIR-TRACE は判定線で切れないことを利用した、AIR-TRACE が出現したら一拍置いて HOLD を押すギミック。AIR-TRACE と HOLD は 0 倍速設定になっている


おまけ

UMIGURI NEW (仮)

UMIGURI v1 に潜在する様々な問題点を解決するために「UMIGURI NEW (仮)」としてほぼ一から開発している新バージョンです。

重かった UI 描画も独自のエンジンで軽量化し、表現力も向上させています。 開発進捗は Twitter @inonote で流しています。

プレイ画面
リザルト画面

※キャプチャ画像は開発中で未完成状態なので完成版は大きく変わっているかもしれません。
※プレイ画面の背景が新しくなっていますが、従来の背景に切り替えることも可能です。



UMIGURI ㊙情報

(ゲームディレクトリ)/data/music のサブディレクトリに .umgrignore の名前で空のファイルを配置すると、起動時の楽曲を収集する際そのディレクトリの存在が無視されます。

楽曲数が多くなるとその分起動時間も長くなりますが、この機能を使うことで起動時間を短縮することができます。

デバッグ機能として実装していたのですが消し忘れました。

例: EXAMPLE ディレクトリを無視したい場合

UMIGURI
┗ data
 ┗ music
  ┗ EXAMPLE
   ┣ 3dBackgroundTest
   ┣ 3dFieldTest
   ┣   ⋮
   ┣ Tutorial
   ┗ .umgrignore   ←こう配置する



好きな配置

一応作譜人 (さくふんちゅ) でもあるので好きな配置を置いておきます。

SLIDE 中継点を等間隔でカチャカチャ鳴らす配置
チャッチャッチャッチャ...って軽快な音が鳴るの好き。

例:

  • Bad Apple!! feat.nomico (MAS)

    ボーカルのリズムを無視して 4 分で音取ることで緩急が生まれる

  • 太陽曰く燃えよカオス (MAS)

    動きが付くと楽しい

  • staple stable (MAS)

    ボーカルに無い音を取っているが前後の流れを崩さない配置

何とは言わないけど星 PLUS から始めた民なので残念ながら一番上以外は遊んだことないです... (復活してくれ)

ノーツの効果音を巧みに使っている配置

楽曲のメロディーの音の高さが上がるのに合わせて AIR-HOLD を配置して高音の効果音を鳴らすようにしています。

また、効果音の高さは TAP → SLIDE 終点 → AIR-HOLD の順で高くなることが知られていますが、この配置は 1 拍目で TAP を鳴らし、 2 拍目で SLIDE 終点 を鳴らし、 3 拍目で AIR-HOLD を鳴らすことで段階的に音が高くなるようになっており、プレイが盛り上がるようになっています。(同時に鳴る効果音の種類も 1 → 2 → 4 と増えてますね。)



最後に

ここまで読んでいただきありがとうございます。
これからチ...ニズムで遊ぶ時はノーツ描画の仕様の知識を活かして、このノーツは描画順があのノーツよりも上だからこんな見た目になってるんだなーとか意識して譜面を見るとより面白くなるかも知れません。僕はしてます。

*1:その場で画面を描画すること。高負荷な処理は極力避け、描画を短時間 (画面の垂直同期の間隔内) で済ませる必要がある。反対にあらかじめ描画しておくことを事前レンダリングという。ゲームの途中に挟まれるムービーなどが大抵それ。

ImageMagick のメモ

基本

  • convert 元の画像を保持
    • 引数の頭に入力画像ファイル名、末尾に出力画像ファイル名。
  • mogrify 上書き
    • 引数の末尾に加工対象の画像ファイル名。

解像度変更

-resize 横x縦

横縦のどちらかを省略すると比率を保持したまま変更。

キャンバスの大きさを変更 (余白を変更)

-gravity 位置 -extent 横x縦

-gravity に指定する方位

northwest  north  northeast
        \    |    /
west ---- center  ---- east
        /    |    \
southwest  south  southeast

画像の透明度を保持して加工する

-background transparent

ひなこのーと のくじ引き

ひなこのーと のくじ引き堂でゲットした商品が届いた。


ウワァァァァァァァァァァァァァァァァァァァ(歓喜)


すこ.........ウッ……死…


財力があればコンプしたかったんですけどね!!!!
(無念)

まとめ

くじ引き堂での売り上げでフィギュア化してくれんかな。受注生産でもいいので

(サムネ用)https://pbs.twimg.com/media/E7rayqkVIAA7VK2?format=jpg&name=large

【PC版 原神】スクリーンショットの保存先の変え方

  • 自己責任で行なってください。
  • インストール先と新たなスクショ保存先のストレージのファイルシステムNTFS 以外の場合は非対応。

1. 新たなスクショ保存先に ScreenShot フォルダを移動する

GenshinImpact.exeがあるインストール先フォルダ (デフォルトで C:\Program Files\Genshin Impact\Genshin Impact game) 内の ScreenShot フォルダを好きな場所に移動します。

※この時フォルダ名が ScreenShot で紛れるかもしれないので、分かりやすく名前変更しても構いません。
f:id:inonote:20210319121947p:plain

2. 管理者権限でコマンドプロンプトを起動する

Winキー + R で「ファイル名を指定して実行」を起動し、「cmd」と打ち込んでから Ctrl + Shift + Enter を押して管理者権限としてコマンドプロンプトを起動します。

3. コマンドを実行する

以下のコマンドをメモ帳などにコピペし、<>内を書き換えてからコマンドプロンプトにコピペし、最後に Enterキー を押します。

pushd "<GenshinImpact.exeがあるインストール先フォルダパス>"
mklink /d "<GenshinImpact.exeがあるインストール先フォルダパス>\ScreenShot" "<新たなスクショ保存先のフォルダパス>"


※フォルダパスは、フォルダを開いた状態でアドレスバーを右クリックし「アドレスのコピー」をクリックすることで簡単にコピペできます。 f:id:inonote:20210319162252p:plain

インストール先フォルダに矢印マークがついたアイコンのScreenShotフォルダが出現したら成功です。原神のカメラ機能でスクショしたら新たなスクショ保存先に保存されるはずです。
f:id:inonote:20210319123001p:plain

※あるフォルダへの入り口を別の場所にも設置するような方法で保存先を変えたので、元のScreenShotフォルダを開いても新たなスクショ保存先と同じ中身なのは正常です



変更した保存先を元に戻す方法

インストール先フォルダにある、矢印マークがついたアイコンのScreenShotフォルダを削除するだけです。