Davinci ResolveでScriptを追加したい。
この情報では、Davinci ResolveはPATH `/usr/local/bin/python3`でPython3を探そうとするので、シンボリックリンクを貼るといい、とありました。これで解決しました。
ln -s `which python3` /usr/local/bin/python3
Davinci ResolveでScriptを追加したい。
この情報では、Davinci ResolveはPATH `/usr/local/bin/python3`でPython3を探そうとするので、シンボリックリンクを貼るといい、とありました。これで解決しました。
ln -s `which python3` /usr/local/bin/python3
MIDI Pianoの入力や演奏の様子を鍵盤上で「見る」だけの手頃でシンプルなVisualizer Pluginがなかったので、久しぶりにC++の復習も兼ねて作ってみた。
【C++の復習】juce::MidiKeyboardStateはPluginProcessor.hでインスタンス化し、その他のComponentではその参照を利用する。
// PluginProcessor.h
class SimplePianoVisualizerAudioProcessor : public juce::AudioProcessor
{
public:
// 省略
juce::MidiKeyboardState& getKeyboardState() {
return keyboardState;
} //インスタンスへの参照をゲットするpublic関数
private:
//==============================================================================
juce::MidiKeyboardState keyboardState; // ここでインスタンス化
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SimplePianoVisualizerAudioProcessor)
};
// PluginEditor.cpp
SimplePianoVisualizerAudioProcessorEditor::SimplePianoVisualizerAudioProcessorEditor (SimplePianoVisualizerAudioProcessor& p)
: AudioProcessorEditor (&p), audioProcessor (p), keyboardState(p.getKeyboardState())
{
setSize (400, 300);
}
【C++の復習】keyboardComponentはPluginEditor.hでインスタンス化し、initialization listでイニシャライズする。
//PluginEditor.h
class SimplePianoVisualizerAudioProcessorEditor : public juce::AudioProcessorEditor
{
public:
SimplePianoVisualizerAudioProcessorEditor (SimplePianoVisualizerAudioProcessor&);
~SimplePianoVisualizerAudioProcessorEditor() override;
//==============================================================================
void paint (juce::Graphics&) override;
void resized() override;
private:
SimplePianoVisualizerAudioProcessor& audioProcessor;
juce::MidiKeyboardState& keyboardState;
juce::MidiKeyboardComponent keyboardComponent;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SimplePianoVisualizerAudioProcessorEditor)
};
//PluginEditor.cpp
SimplePianoVisualizerAudioProcessorEditor::SimplePianoVisualizerAudioProcessorEditor (SimplePianoVisualizerAudioProcessor& p)
: AudioProcessorEditor (&p), audioProcessor (p), keyboardState(p.getKeyboardState()), keyboardComponent(p.getKeyboardState(), juce::KeyboardComponentBase::horizontalKeyboard)
{
setSize (400, 300);
}
【JUCEの復習】PluginEditor.cppのコンストラクタとresized()に記述し、画面上に表示する。
// Constructor
{
addAndMakeVisible(keyboardComponent);
setSize (400, 100);
setResizable(true, false);
}
// resized()
void SimplePianoVisualizerAudioProcessorEditor::resized()
{
auto area = getLocalBounds();
keyboardComponent.setBounds(area);
}
これを実行すると、以下のように表示されます。縦・横を自由に表示されるようにするには、Sliderなどでサイズを可変にすると良いです。
void SimplePianoVisualizerAudioProcessorEditor::sliderValueChanged(juce::Slider *slider)
{
horizontalSliderValue = horizontalSlider.getValue();
verticalSliderValue = verticalSlider.getValue();
// making sure the resized() (UI changes) are made on the UI thread
(new SliderValueChangedCallback(this))->post();
}
void SimplePianoVisualizerAudioProcessorEditor::resized()
{
auto area = getLocalBounds();
auto verticalMargin = area.getHeight()/2.8;
auto keyboardArea = area.removeFromBottom(verticalMargin).reduced(30, 0);
keyWidth = 32 * (horizontalSliderValue/10);
keyboardComponent.setKeyWidth(keyWidth);
keyboardComponent.setBounds(keyboardArea.getX(), keyboardArea.getY(), keyboardArea.getWidth(), keyboardArea.getHeight()*(verticalSliderValue/10));
}
PluginProcessorのprocessBlockで下のように処理をすると、キーボードを弾くとスクリーン上のキーボードが反応するようになります。
void SimplePianoVisualizerAudioProcessor::processBlock (juce::AudioBuffer<float>& buffer, juce::MidiBuffer& midiMessages)
{
for(const auto m: midiMessages) {
keyboardState.processNextMidiEvent(m.getMessage());
}
}
以下は、毎月28日の9時17分にcertbot renew とnginxのリスタートを実行し、その結果をcertbot_renew_logファイルにlogするcron jobです。taskを( )で囲まないとlogできませんでした。
17 9 28 * * (certbot renew && systemctl restart nginx) >> /var/log/certbot_renew_log 2>&1
// activity
public class MainActivity extends AppCompatActivity {
Button button1;
@SuppressLint("ClickableViewAccessibility")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getSupportActionBar().hide();
RelativeLayout rootLinearLayout = new RelativeLayout(this);
rootLinearLayout.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT));
rootLinearLayout.setBackgroundColor(Color.CYAN);
setContentView(rootLinearLayout);
OvalShape ovalShape = new OvalShape();
ShapeDrawable shapeDrawable = new ShapeDrawable(ovalShape);
shapeDrawable.getPaint().setColor(Color.GRAY); // Change this to your desired color.
button1 = new Button(this);
button1.setText("Task1");
int button1Id = View.generateViewId();
button1.setId(button1Id);
int size = 200; // Change this to your desired size.
RelativeLayout.LayoutParams buttonLP = new RelativeLayout.LayoutParams(size, size);
buttonLP.addRule(RelativeLayout.CENTER_IN_PARENT);
RelativeLayout.LayoutParams buttonLP1 = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
buttonLP1.addRule(RelativeLayout.CENTER_IN_PARENT);
button1.setLayoutParams(buttonLP);
button1.setOnClickListener(new OnButtonClicked());
button1.setOnTouchListener(new OnButtonTouched(Color.GRAY, Color.BLUE));
button1.setBackground(shapeDrawable);
rootLinearLayout.addView(button1);
}
}
// custom onTouchListener
public class OnButtonTouched implements View.OnTouchListener {
private final int normalColor;
private final int pressedColor;
private static final String TAG = "ButtonClicked";
public OnButtonTouched(int normalColor, int pressedColor) {
this.normalColor = normalColor;
this.pressedColor = pressedColor;
}
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.d(TAG, "in touched");
if (!(v.getBackground() instanceof ShapeDrawable)) {
return false; // Return false if the background is not of the expected type
}
ShapeDrawable shapeDrawable = (ShapeDrawable) v.getBackground();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// Button pressed: change color
shapeDrawable.getPaint().setColor(pressedColor);
v.invalidate(); // Force the button to be redrawn
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
// Button released or touch cancelled: revert to original color
shapeDrawable.getPaint().setColor(normalColor);
v.invalidate(); // Force the button to be redrawn
break;
}
return false; // Return false to indicate not to consume touch events, let them propagate so the onClick events will fire.
}
}
これは僕が知らなかったのでメモしておきます。ComboBoxはcomboBox.addItem(“string”, counter);でアイテムを追加出来ますが、このcounterはアイテムが追加される順番だと思っていましたが、intであればなんでもいいようです。
つまり、何かのデータのindexなどをこれにあてることで、comboBox.getSelectedId()で値をゲットできるので、とても便利です。
カスタムComponentにTooltipをセットしたい場合は、public juce::SettableTooltipClientを継承する必要があります。
class CustomComponent : public juce::Component, public juce::SettableTooltipClient
{
};
Child ComponentがParent Componentのエリアを全て覆ってしまっている場合、Parent ComponentのMouseEventが実行されませんが、以下のようにoverrideすると実行されるようになります。
class ForwardingLabel : public juce::Label
{
public:
ForwardingLabel()
{
}
void mouseDown(const juce::MouseEvent &event) override {
if(auto parent = getParentComponent()) {
parent->mouseDown(event);
}
}
void mouseExit(const juce::MouseEvent &event) override {
if(auto parent = getParentComponent()) {
parent->mouseExit(event);
}
}
private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ForwardingLabel)
};
JUCEのAudioProcessorValueTreeStateのパラメターを使う場合、以下のようなシナリオがあると思います。
auto param = valueTreeState.getParameterAsValue(ParamId);
// getting value
int paramValue = param.getValue();
// setting value
param.setValue(juce::var(newValue));
2. パラメターのリアルタイム値をゲットしたい場合
int value = (int)*valueTreeState.getRawParameterValue(ParamId);
Host(DAW)に保存されているパラメターをPlug-In再起動時に読み込む場合などは、getRawParameterValueを使わないといけないようです。
JUCEでThreadIDを確認するには以下の方法があります。
// get threadID
void* currentThreadId = juce::Thread::getCurrentThreadId();
DBG("setSelectorId thread ID: " + juce::String(reinterpret_cast<uintptr_t>(currentThreadId)));
// check if the thread is the Message Thread
bool isMessageThread = juce::MessageManager::getInstance()->isThisTheMessageThread();
DBG("Is this message thread? " + juce::String(isMessageThread ? "YES" : "NO"));
ComboBoxの操作において、プログラム的に操作をする場合とユーザーが手動で操作をする場合において、異なるcallback処理をしたい場合は、以下のようにCustomComboBoxクラスのmouseDown()をoverrideするといいと思います。
class CustomComboBox : public juce::ComboBox
{
public:
CustomComboBox() : juce::ComboBox()
{
}
~CustomComboBox() override
{
}
void mouseDown(const juce::MouseEvent &event) override {
DBG("Mouse down");
userInteracted = true;
juce::ComboBox::mouseDown(event);
}
bool getUserInteracted() const {
return userInteracted;
}
void setUserInteractedToFalse() {
userInteracted = false;
}
private:
bool userInteracted = false;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CustomComboBox)
};
void comboBoxChanged(juce::ComboBox *comboBoxThatHasChanged) override {
if (comboBoxThatHasChanged == &selector) {
if(selector.getUserInteracted()) {
DBG("user selected ...");
// do something
selector.setUserInteractedToFalse();
} else {
DBG("program selected ...");
// do something
}
}
}