diff --git a/stuff/config/current.txt b/stuff/config/current.txt
index 62c5c93..19e32cf 100644
--- a/stuff/config/current.txt
+++ b/stuff/config/current.txt
@@ -1255,6 +1255,19 @@
   <item>"STD_iwa_BarrelDistortFx.vignetteMidpoint" "Vignetting Midpoint"</item>
   <item>"STD_iwa_BarrelDistortFx.scale" "Scale"</item>
 
+  <item>"STD_iwa_TextFx"	"Text Iwa"</item>
+  <item>"STD_iwa_TextFx.targetType" "Source"</item>
+  <item>"STD_iwa_TextFx.columnIndex" "Column Index"</item>
+  <item>"STD_iwa_TextFx.hAlign" "Holizontal Align"</item>
+  <item>"STD_iwa_TextFx.text" "Text"</item>
+  <item>"STD_iwa_TextFx.center" "Center"</item>
+  <item>"STD_iwa_TextFx.width" "Width"</item>
+  <item>"STD_iwa_TextFx.height" "Height"</item>
+  <item>"STD_iwa_TextFx.font" "Font"</item>
+  <item>"STD_iwa_TextFx.textColor" "Text Color"</item>
+  <item>"STD_iwa_TextFx.boxColor" "Box Color"</item>
+  <item>"STD_iwa_TextFx.showBorder" "Show Border"</item>
+
  <!------------------------------ Tiled Particles Iwa ------------------------------------------->
 
   <item>STD_iwa_TiledParticlesFx "Tiled Particles Iwa" </item>
diff --git a/stuff/profiles/layouts/fxs/STD_iwa_TextFx.xml b/stuff/profiles/layouts/fxs/STD_iwa_TextFx.xml
new file mode 100644
index 0000000..aab4c54
--- /dev/null
+++ b/stuff/profiles/layouts/fxs/STD_iwa_TextFx.xml
@@ -0,0 +1,17 @@
+<fxlayout>
+	<page name="Text Iwa">
+ 	<vbox>
+		<control>targetType</control>
+		<control>columnIndex</control>
+		<control>text</control>
+		<control>hAlign</control>
+		<control>center</control>
+		<control>width</control>
+		<control>height</control>
+		<control>font</control>
+		<control>textColor</control>
+		<control>boxColor</control>
+		<control>showBorder</control>
+  	</vbox>
+  	</page>
+</fxlayout>
diff --git a/stuff/profiles/layouts/fxs/fxs.lst b/stuff/profiles/layouts/fxs/fxs.lst
index 126bc35..622ed46 100644
--- a/stuff/profiles/layouts/fxs/fxs.lst
+++ b/stuff/profiles/layouts/fxs/fxs.lst
@@ -146,7 +146,8 @@
     STD_inopnCloudsFx
     STD_particlesFx 
     STD_iwa_TiledParticlesFx
-    STD_iwa_TimeCodeFx
+    STD_iwa_PNPerspectiveFx
+    STD_iwa_TextFx
   </Render>
   <Stylize>
     STD_colorEmbossFx
diff --git a/toonz/sources/common/tparam/tnotanimatableparam.cpp b/toonz/sources/common/tparam/tnotanimatableparam.cpp
index dc89a62..ea206f7 100644
--- a/toonz/sources/common/tparam/tnotanimatableparam.cpp
+++ b/toonz/sources/common/tparam/tnotanimatableparam.cpp
@@ -8,6 +8,7 @@ PERSIST_IDENTIFIER(TBoolParam, "boolParam")
 PERSIST_IDENTIFIER(TFilePathParam, "filePathParam")
 PERSIST_IDENTIFIER(TStringParam, "stringParam")
 PERSIST_IDENTIFIER(TNADoubleParam, "naDoubleParam")
+PERSIST_IDENTIFIER(TFontParam, "fontParam")
 // PERSIST_IDENTIFIER(TIntEnumParam, "intEnumParam")
 
 TPersistDeclarationT<TEnumParam> TEnumParam::m_declaration("intEnumParam");
@@ -94,6 +95,17 @@ void TNADoubleParam::saveData(TOStream &os) {
   os << getDefaultValue();
   os << getValue();
 }
+
+//=========================================================
+
+void TFontParam::loadData(TIStream &is) {
+  std::wstring str;
+  is >> str;
+  setValue(str, false);
+}
+
+void TFontParam::saveData(TOStream &os) { os << getValue(); }
+
 //=========================================================
 
 //=========================================================
diff --git a/toonz/sources/include/tnotanimatableparam.h b/toonz/sources/include/tnotanimatableparam.h
index b28497d..d61f07b 100644
--- a/toonz/sources/include/tnotanimatableparam.h
+++ b/toonz/sources/include/tnotanimatableparam.h
@@ -13,6 +13,7 @@
 #include "tconvert.h"
 
 #include <set>
+#include <QFont>
 
 #undef DVAPI
 #undef DVVAR
@@ -169,6 +170,7 @@ public:
     using namespace std;
     return to_string(getValue());
   }
+
   bool hasKeyframes() const override { return 0; };
   void getKeyframes(std::set<double> &) const override{};
   int getNextKeyframe(double) const override { return -1; };
@@ -280,6 +282,8 @@ template class DVAPI TPersistDeclarationT<TStringParam>;
 class DVAPI TStringParam final : public TNotAnimatableParam<std::wstring> {
   PERSIST_DECLARATION(TStringParam);
 
+  bool m_multiLine = false;
+
 public:
   TStringParam(std::wstring v = L"") : TNotAnimatableParam<std::wstring>(v) {}
   TStringParam(const TStringParam &src)
@@ -287,6 +291,9 @@ public:
   TParam *clone() const override { return new TStringParam(*this); }
   void loadData(TIStream &is) override;
   void saveData(TOStream &os) override;
+
+  void setMultiLineEnabled(bool enable) { m_multiLine = enable; }
+  bool isMultiLineEnabled() { return m_multiLine; }
 };
 
 DEFINE_PARAM_SMARTPOINTER(TStringParam, std::wstring)
@@ -393,6 +400,32 @@ private:
 
 DEFINE_PARAM_SMARTPOINTER(TNADoubleParam, double)
 
+//=========================================================
+//
+//  class TFontParam
+//
+//=========================================================
+
+#ifdef _WIN32
+template class DVAPI TNotAnimatableParam<std::wstring>;
+class TFontParam;
+template class DVAPI TPersistDeclarationT<TFontParam>;
+#endif
+
+class DVAPI TFontParam final : public TNotAnimatableParam<std::wstring> {
+  PERSIST_DECLARATION(TFontParam);
+
+public:
+  TFontParam(std::wstring v = QFont().toString().toStdWString())
+      : TNotAnimatableParam<std::wstring>(v) {}
+  TFontParam(const TFontParam &src) : TNotAnimatableParam<std::wstring>(src) {}
+  TParam *clone() const override { return new TFontParam(*this); }
+  void loadData(TIStream &is) override;
+  void saveData(TOStream &os) override;
+};
+
+DEFINE_PARAM_SMARTPOINTER(TFontParam, std::wstring)
+
 //-----------------------------------------------------------------------------
 //  TNotAnimatableParamChangeUndo
 //-----------------------------------------------------------------------------
diff --git a/toonz/sources/include/toonzqt/paramfield.h b/toonz/sources/include/toonzqt/paramfield.h
index 858f823..dbf3880 100644
--- a/toonz/sources/include/toonzqt/paramfield.h
+++ b/toonz/sources/include/toonzqt/paramfield.h
@@ -15,6 +15,7 @@
 #include <QButtonGroup>
 #include <QRadioButton>
 #include <QPushButton>
+#include <QTextEdit>
 
 #include "tgeometry.h"
 #include "tparam.h"
@@ -40,6 +41,7 @@ class QString;
 class QComboBox;
 class QHBoxLayout;
 class TFxHandle;
+class QFontComboBox;
 
 namespace DVGui {
 class LineEdit;
@@ -501,11 +503,28 @@ protected slots:
 // StringParamField
 //-----------------------------------------------------------------------------
 
+namespace component {
+class MyTextEdit : public QTextEdit {
+  Q_OBJECT
+public:
+  MyTextEdit(const QString &text, QWidget *parent = Q_NULLPTR)
+      : QTextEdit(text, parent) {}
+
+protected:
+  void keyPressEvent(QKeyEvent *event) override;
+  void focusOutEvent(QFocusEvent *e) override;
+
+signals:
+  void edited();
+};
+};
+
 class DVAPI StringParamField final : public ParamField {
   Q_OBJECT
 
   TStringParamP m_currentParam, m_actualParam;
-  DVGui::LineEdit *m_textFld;
+  DVGui::LineEdit *m_textFld            = nullptr;
+  component::MyTextEdit *m_multiTextFld = nullptr;
 
 public:
   StringParamField(QWidget *parent, QString name, const TStringParamP &param);
@@ -514,8 +533,41 @@ public:
                 int frame) override;
   void update(int frame) override;
 
-  QSize getPreferedSize() override { return QSize(100, 20); }
+  QSize getPreferedSize() override {
+    if (m_textFld)
+      return QSize(100, 20);
+    else
+      return QSize(100, 80);
+  }
+protected slots:
+  void onChange();
+};
+
+//=============================================================================
+// FontParamField
+//-----------------------------------------------------------------------------
+
+class FontParamField final : public ParamField {
+  Q_OBJECT
+
+  TFontParamP m_currentParam, m_actualParam;
+
+  QFontComboBox *m_fontCombo;
+  QComboBox *m_styleCombo;
+  DVGui::IntField *m_sizeField;
+
+public:
+  FontParamField(QWidget *parent, QString name, const TFontParamP &param);
+
+  void setParam(const TParamP &current, const TParamP &actual,
+                int frame) override;
+  void update(int frame) override;
+
+  QSize getPreferedSize() override { return QSize(150, 20); }
+
 protected slots:
+  void findStyles(const QFont &font);
+  void onSizeChange(bool);
   void onChange();
 };
 
diff --git a/toonz/sources/stdfx/CMakeLists.txt b/toonz/sources/stdfx/CMakeLists.txt
index b691a4e..f0a0017 100644
--- a/toonz/sources/stdfx/CMakeLists.txt
+++ b/toonz/sources/stdfx/CMakeLists.txt
@@ -72,9 +72,10 @@ set(HEADERS
     iwa_fresnel.h
     iwa_pnperspectivefx.h
     iwa_soapbubblefx.h
-	iwa_bokehfx.h
-	iwa_timecodefx.h
-	iwa_bokehreffx.h
+    iwa_bokehfx.h
+    iwa_timecodefx.h
+    iwa_bokehreffx.h
+    iwa_textfx.h
 )
 
 set(SOURCES
@@ -250,12 +251,13 @@ set(SOURCES
     iwa_noise1234.cpp
     iwa_pnperspectivefx.cpp
     iwa_soapbubblefx.cpp
-	${SDKROOT}/kiss_fft130/kiss_fft.c
-	${SDKROOT}/kiss_fft130/tools/kiss_fftnd.c
-	iwa_bokehfx.cpp
-	iwa_timecodefx.cpp
-	iwa_bokehreffx.cpp
-	iwa_barreldistortfx.cpp
+    ${SDKROOT}/kiss_fft130/kiss_fft.c
+    ${SDKROOT}/kiss_fft130/tools/kiss_fftnd.c
+    iwa_bokehfx.cpp
+    iwa_timecodefx.cpp
+    iwa_bokehreffx.cpp
+    iwa_barreldistortfx.cpp
+    iwa_textfx.cpp
 )
 
 set(OBJCSOURCES
diff --git a/toonz/sources/stdfx/iwa_textfx.cpp b/toonz/sources/stdfx/iwa_textfx.cpp
new file mode 100644
index 0000000..41892f0
--- /dev/null
+++ b/toonz/sources/stdfx/iwa_textfx.cpp
@@ -0,0 +1,250 @@
+#include "iwa_textfx.h"
+
+#include "tparamuiconcept.h"
+#include <QFontMetrics>
+#include <QImage>
+#include <QPainter>
+
+//------------------------------------------------------------------
+
+Iwa_TextFx::Iwa_TextFx()
+    : m_text(L"Lorem ipsum")
+    , m_hAlign(new TIntEnumParam(Qt::AlignLeft, "Left"))
+    , m_center(TPointD(0.0, 0.0))
+    , m_width(200.0)
+    , m_height(60.0)
+    , m_font(new TFontParam())
+    , m_textColor(TPixel32::Black)
+    , m_boxColor(TPixel32::Transparent)
+    , m_showBorder(false) {
+  m_targetType->setValue(INPUT_TEXT);
+
+  m_hAlign->addItem(Qt::AlignRight, "Right");
+  m_hAlign->addItem(Qt::AlignHCenter, "Center");
+  m_hAlign->addItem(Qt::AlignJustify, "Justify");
+
+  m_text->setMultiLineEnabled(true);
+
+  m_center->getX()->setMeasureName("fxLength");
+  m_center->getY()->setMeasureName("fxLength");
+  m_width->setMeasureName("fxLength");
+  m_height->setMeasureName("fxLength");
+
+  m_width->setValueRange(1.0, (std::numeric_limits<double>::max)());
+  m_height->setValueRange(1.0, (std::numeric_limits<double>::max)());
+
+  // set the initial font size to 30
+  QFont font;
+  font.fromString(QString::fromStdWString(m_font->getValue()));
+  font.setPixelSize(30);
+  m_font->setValue(font.toString().toStdWString(), true);
+
+  bindParam(this, "targetType", m_targetType);
+  bindParam(this, "columnIndex", m_columnIndex);
+  bindParam(this, "text", m_text);
+  bindParam(this, "hAlign", m_hAlign);
+  bindParam(this, "center", m_center);
+  bindParam(this, "width", m_width);
+  bindParam(this, "height", m_height);
+  bindParam(this, "font", m_font);
+  bindParam(this, "textColor", m_textColor);
+  bindParam(this, "boxColor", m_boxColor);
+  bindParam(this, "showBorder", m_showBorder);
+}
+
+//------------------------------------------------------------------
+
+bool Iwa_TextFx::doGetBBox(double frame, TRectD &bBox,
+                           const TRenderSettings &ri) {
+  bBox = TConsts::infiniteRectD;
+  return true;
+}
+
+//------------------------------------------------------------------
+
+void Iwa_TextFx::doCompute(TTile &tile, double frame,
+                           const TRenderSettings &ri) {
+  QString text;
+  if (m_targetType->getValue() == INPUT_TEXT)
+    text = QString::fromStdWString(m_text->getValue());
+  else
+    text = m_noteLevelStr;
+  if (text.isEmpty()) return;
+
+  QFont font;
+  font.fromString(QString::fromStdWString(m_font->getValue()));
+
+  double fac = sqrt(fabs(ri.m_affine.det()));
+  int size   = (int)(fac * fabs(font.pixelSize()));
+
+  TPoint center = convert(
+      fac * m_center->getValue(frame) -
+      (tile.m_pos + tile.getRaster()->getCenterD()) +
+      TPointD(ri.m_cameraBox.getLx() / 2.0, ri.m_cameraBox.getLy() / 2.0));
+
+  QRect textBoxRect(0, 0, fac * m_width->getValue(frame),
+                    fac * m_height->getValue(frame));
+  textBoxRect.moveCenter(QPoint(center.x, center.y));
+
+  Qt::AlignmentFlag hAlignFlag = (Qt::AlignmentFlag)m_hAlign->getValue();
+
+  // For simplification, text will always be "wrapped".
+  // If user would like to make the line with no break, they can just expand the
+  // boundary or set the smaller font size.
+  int flag = hAlignFlag | Qt::AlignVCenter | Qt::TextWordWrap;
+
+  QFont tmpFont(font);
+  tmpFont.setPixelSize(100);
+  QFontMetricsF tmpFm(tmpFont);
+  QRectF bbox = tmpFm.boundingRect(textBoxRect, flag, text);
+
+  float ratio = std::min(textBoxRect.width() / bbox.width(),
+                         textBoxRect.height() / bbox.height());
+
+  // compute the font size which will just fit the item region
+  int fontSize = (int)(100.0f * ratio);
+  tmpFont.setPixelSize(fontSize);
+  tmpFm = QFontMetricsF(tmpFont);
+  bbox  = tmpFm.boundingRect(textBoxRect, flag, text);
+  bool isInRect;
+  if (textBoxRect.width() >= bbox.width() &&
+      textBoxRect.height() >= bbox.height())
+    isInRect = true;
+  else
+    isInRect = false;
+  while (1) {
+    fontSize += (isInRect) ? 1 : -1;
+    if (fontSize <= 0)  // cannot draw
+      return;
+    if (isInRect && fontSize >= size) break;
+    tmpFont.setPixelSize(fontSize);
+    tmpFm = QFontMetricsF(tmpFont);
+    bbox  = tmpFm.boundingRect(textBoxRect, flag, text);
+
+    bool newIsInRect = (textBoxRect.width() >= bbox.width() &&
+                        textBoxRect.height() >= bbox.height());
+    if (isInRect != newIsInRect) {
+      if (isInRect) fontSize--;
+      break;
+    }
+  }
+
+  if (size < fontSize) {
+    fontSize = size;
+  }
+
+  font.setPixelSize(fontSize);
+  tmpFm = QFontMetricsF(font);
+  bbox  = tmpFm.boundingRect(textBoxRect, flag, text);
+
+  double lineWidth = 0.1 * (double)fontSize;
+
+  // Usually the text bounding box has less horizontal margin than vertical.
+  // So here I added more margin to width.
+  QImage img(bbox.width() + (int)(lineWidth * 4),
+             bbox.height() + (int)(lineWidth * 2),
+             QImage::Format_ARGB32_Premultiplied);
+  img.fill(Qt::transparent);
+
+  bbox.moveCenter(img.rect().center());
+
+  QPainter painter(&img);
+  TPixel32 boxColor = m_boxColor->getValue(frame);
+  TPixel32 color    = m_textColor->getValue(frame);
+
+  if (boxColor.m > 0)
+    painter.fillRect(img.rect(), QColor((int)boxColor.r, (int)boxColor.g,
+                                        (int)boxColor.b, (int)boxColor.m));
+
+  QPen pen(QColor((int)color.r, (int)color.g, (int)color.b, (int)color.m));
+  painter.setPen(pen);
+  painter.setFont(font);
+  painter.drawText(bbox, flag, text);
+
+  if (m_showBorder->getValue()) {
+    pen.setWidthF(lineWidth);
+    pen.setJoinStyle(Qt::MiterJoin);
+    painter.setPen(pen);
+    painter.drawRect(img.rect().adjusted(lineWidth / 2, lineWidth / 2,
+                                         -lineWidth / 2, -lineWidth / 2));
+  }
+
+  TPoint imgRootPos = center - TPoint(img.width() / 2, img.height() / 2);
+
+  tile.getRaster()->clear();
+  TRaster32P ras32 = (TRaster32P)tile.getRaster();
+  TRaster64P ras64 = (TRaster64P)tile.getRaster();
+  if (ras32)
+    putTextImage<TRaster32P, TPixel32>(ras32, imgRootPos, img);
+  else if (ras64)
+    putTextImage<TRaster64P, TPixel64>(ras64, imgRootPos, img);
+  else
+    throw TException("Iwa_TextFx: unsupported Pixel Type");
+}
+
+//------------------------------------------------------------------
+
+void Iwa_TextFx::getParamUIs(TParamUIConcept *&concepts, int &length) {
+  concepts = new TParamUIConcept[length = 2];
+
+  concepts[0].m_type  = TParamUIConcept::POINT;
+  concepts[0].m_label = "Center";
+  concepts[0].m_params.push_back(m_center);
+
+  concepts[1].m_type = TParamUIConcept::RECT;
+  concepts[1].m_params.push_back(m_width);
+  concepts[1].m_params.push_back(m_height);
+  concepts[1].m_params.push_back(m_center);
+}
+
+//------------------------------------------------------------------
+
+std::string Iwa_TextFx::getAlias(double frame,
+                                 const TRenderSettings &info) const {
+  std::string alias = getFxType();
+  alias += "[";
+
+  std::string paramalias("");
+  for (int i = 0; i < getParams()->getParamCount(); ++i) {
+    TParam *param = getParams()->getParam(i);
+    paramalias += param->getName() + "=" + param->getValueAlias(frame, 3);
+  }
+
+  if (m_targetType->getValue() == INPUT_TEXT)
+    return alias + "," + std::to_string(getIdentifier()) + paramalias + "]";
+  else
+    return alias + std::to_string(frame) + "," +
+           std::to_string(getIdentifier()) + paramalias + "]";
+}
+
+//------------------------------------------------------------------
+
+template <typename RASTER, typename PIXEL>
+void Iwa_TextFx::putTextImage(const RASTER srcRas, TPoint &pos, QImage &img) {
+  for (int j = 0; j < img.height(); j++) {
+    int rasY = pos.y + j;
+    if (rasY < 0) continue;
+    if (srcRas->getLy() <= rasY) break;
+
+    PIXEL *pix  = srcRas->pixels(rasY);
+    QRgb *img_p = (QRgb *)img.scanLine(img.height() - j - 1);
+    for (int i = 0; i < img.width(); i++, img_p++) {
+      int rasX = pos.x + i;
+      if (rasX < 0) continue;
+      if (srcRas->getLx() <= rasX) break;
+
+      pix[rasX].r = (typename PIXEL::Channel)(
+          qRed(*img_p) * (int)PIXEL::maxChannelValue / (int)UCHAR_MAX);
+      pix[rasX].g = (typename PIXEL::Channel)(
+          qGreen(*img_p) * (int)PIXEL::maxChannelValue / (int)UCHAR_MAX);
+      pix[rasX].b = (typename PIXEL::Channel)(
+          qBlue(*img_p) * (int)PIXEL::maxChannelValue / (int)UCHAR_MAX);
+      pix[rasX].m = (typename PIXEL::Channel)(
+          qAlpha(*img_p) * (int)PIXEL::maxChannelValue / (int)UCHAR_MAX);
+    }
+  }
+}
+
+//==============================================================================
+
+FX_PLUGIN_IDENTIFIER(Iwa_TextFx, "iwa_TextFx");
\ No newline at end of file
diff --git a/toonz/sources/stdfx/iwa_textfx.h b/toonz/sources/stdfx/iwa_textfx.h
new file mode 100644
index 0000000..24ea20e
--- /dev/null
+++ b/toonz/sources/stdfx/iwa_textfx.h
@@ -0,0 +1,47 @@
+#pragma once
+
+#ifndef IWA_TEXTFX_H
+#define IWA_TEXTFX_H
+
+#include "tparamset.h"
+#include "textawarebasefx.h"
+
+//******************************************************************
+//	Iwa_Text Fx  class
+//******************************************************************
+
+class Iwa_TextFx final : public TextAwareBaseFx {
+  FX_PLUGIN_DECLARATION(Iwa_TextFx)
+protected:
+  TStringParamP m_text;
+
+  TIntEnumParamP m_hAlign;
+
+  TPointParamP m_center;
+  TDoubleParamP m_width;
+  TDoubleParamP m_height;
+
+  TFontParamP m_font;
+  TPixelParamP m_textColor;
+  TPixelParamP m_boxColor;
+  TBoolParamP m_showBorder;
+
+  template <typename RASTER, typename PIXEL>
+  void putTextImage(const RASTER srcRas, TPoint &pos, QImage &img);
+
+public:
+  Iwa_TextFx();
+
+  bool canHandle(const TRenderSettings &info, double frame) override {
+    return true;
+  }
+
+  bool doGetBBox(double frame, TRectD &bBox,
+                 const TRenderSettings &ri) override;
+  void doCompute(TTile &tile, double frame, const TRenderSettings &ri) override;
+  void getParamUIs(TParamUIConcept *&concepts, int &length) override;
+
+  std::string getAlias(double frame,
+                       const TRenderSettings &info) const override;
+};
+#endif
\ No newline at end of file
diff --git a/toonz/sources/stdfx/textawarebasefx.h b/toonz/sources/stdfx/textawarebasefx.h
new file mode 100644
index 0000000..a25b0da
--- /dev/null
+++ b/toonz/sources/stdfx/textawarebasefx.h
@@ -0,0 +1,32 @@
+#pragma once
+#ifndef TEXTAWAREBASEFX_H
+#define TEXTAWAREBASEFX_H
+
+#include "tfxparam.h"
+#include "stdfx.h"
+
+class TextAwareBaseFx : public TStandardZeraryFx {
+protected:
+  QString m_noteLevelStr;
+
+  TIntEnumParamP m_targetType;
+  TIntParamP m_columnIndex;
+
+public:
+  enum SourceType { NEARBY_COLUMN, SPECIFIED_COLUMN, INPUT_TEXT };
+
+  TextAwareBaseFx()
+      : m_targetType(new TIntEnumParam(NEARBY_COLUMN, "Nearby Note Column"))
+      , m_columnIndex(0) {
+    m_targetType->addItem(SPECIFIED_COLUMN, "Specified Note Column");
+    m_targetType->addItem(INPUT_TEXT, "Input Text");
+  }
+
+  bool isZerary() const override { return true; }
+
+  void setNoteLevelStr(QString str) { m_noteLevelStr = str; }
+  SourceType getSourceType() { return (SourceType)(m_targetType->getValue()); }
+  int getNoteColumnIndex() { return m_columnIndex->getValue() - 1; }
+};
+
+#endif
diff --git a/toonz/sources/toonzlib/scenefx.cpp b/toonz/sources/toonzlib/scenefx.cpp
index e903d80..64672fb 100644
--- a/toonz/sources/toonzlib/scenefx.cpp
+++ b/toonz/sources/toonzlib/scenefx.cpp
@@ -28,8 +28,11 @@
 #include "toonz/stage.h"
 #include "toonz/preferences.h"
 #include "ttzpimagefx.h"
+#include "toonz/txshsoundtextcolumn.h"
+#include "toonz/txshsoundtextlevel.h"
 
 #include "../stdfx/motionawarebasefx.h"
+#include "../stdfx/textawarebasefx.h"
 
 #include "toonz/scenefx.h"
 
@@ -497,6 +500,26 @@ static QList<TPointD> getColumnMotionPoints(TXsheet *xsh, double row, int col,
   return points;
 }
 
+namespace {
+
+QString getNoteText(TXsheet *xsh, double row, int col, int noteColumnIndex,
+                    bool neighbor) {
+  int colIndex;
+  if (neighbor)
+    colIndex = col - 1;
+  else
+    colIndex = noteColumnIndex;
+
+  TXshColumn *column = xsh->getColumn(colIndex);
+  if (!column || !column->getSoundTextColumn()) return QString();
+
+  TXshCell cell = xsh->getCell(row, colIndex);
+  if (cell.isEmpty() || !cell.getSoundTextLevel()) return QString();
+
+  return cell.getSoundTextLevel()->getFrameText(cell.m_frameId.getNumber() - 1);
+}
+};
+
 //***************************************************************************************************
 //    FxBuilder  definition
 //***************************************************************************************************
@@ -939,6 +962,18 @@ PlacedFx FxBuilder::makePF(TZeraryColumnFx *zcfx) {
     }
   }
 
+  if (pf.m_fx->getFxType() == "STD_iwa_TextFx") {
+    TextAwareBaseFx *textFx =
+        dynamic_cast<TextAwareBaseFx *>(pf.m_fx.getPointer());
+    if (textFx && textFx->getSourceType() != TextAwareBaseFx::INPUT_TEXT) {
+      int noteColumnIndex = textFx->getNoteColumnIndex();
+      bool getNeighbor =
+          (textFx->getSourceType() == TextAwareBaseFx::NEARBY_COLUMN);
+      textFx->setNoteLevelStr(getNoteText(m_xsh, m_frame, pf.m_columnIndex,
+                                          noteColumnIndex, getNeighbor));
+    }
+  }
+
   // Add the column placement NaAffineFx
   if (getColumnPlacement(pf, m_xsh, m_frame, pf.m_columnIndex, m_isPreview))
     return pf;
diff --git a/toonz/sources/toonzqt/paramfield.cpp b/toonz/sources/toonzqt/paramfield.cpp
index 5c899ec..3c1f114 100644
--- a/toonz/sources/toonzqt/paramfield.cpp
+++ b/toonz/sources/toonzqt/paramfield.cpp
@@ -20,6 +20,8 @@
 #include <QLabel>
 #include <QPainter>
 #include <QComboBox>
+#include <QFontComboBox>
+#include <QKeyEvent>
 
 using namespace DVGui;
 
@@ -448,6 +450,38 @@ public:
 };
 
 //-----------------------------------------------------------------------------
+/*! FontParamFieldUndo
+*/
+class FontParamFieldUndo final : public FxSettingsUndo {
+  TFontParamP m_param;
+  std::wstring m_oldValue, m_newValue;
+
+public:
+  FontParamFieldUndo(const TFontParamP param, QString name, TFxHandle *fxHandle)
+      : FxSettingsUndo(name, fxHandle), m_param(param) {
+    m_oldValue = param->getValue();
+    m_newValue = m_oldValue;
+  }
+
+  void onAdd() override { m_newValue = m_param->getValue(); }
+
+  void undo() const override {
+    m_param->setValue(m_oldValue);
+    if (m_fxHandle) m_fxHandle->notifyFxChanged();
+  }
+
+  void redo() const override {
+    m_param->setValue(m_newValue);
+    if (m_fxHandle) m_fxHandle->notifyFxChanged();
+  }
+
+  QString getHistoryString() override {
+    QString str = QObject::tr("Modify Fx Param : %1").arg(m_name);
+    return str;
+  }
+};
+
+//-----------------------------------------------------------------------------
 /*! ToneCurveParamField Undo
 */
 class ToneCurveParamFieldUndo final : public AnimatableFxSettingsUndo {
@@ -1395,17 +1429,42 @@ void IntParamField::update(int frame) {
 // StringParamField
 //-----------------------------------------------------------------------------
 
+namespace component {
+
+void MyTextEdit::keyPressEvent(QKeyEvent *event) {
+  QTextEdit::keyPressEvent(event);
+  if (event->key() == Qt::Key_Return) emit edited();
+}
+
+void MyTextEdit::focusOutEvent(QFocusEvent *event) {
+  QTextEdit::focusOutEvent(event);
+  emit edited();
+}
+};
+
 StringParamField::StringParamField(QWidget *parent, QString name,
                                    const TStringParamP &param)
     : ParamField(parent, name, param) {
   QString str;
   m_paramName = str.fromStdString(param->getName());
-  m_textFld   = new LineEdit(name, this);
-  m_textFld->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
-  bool ret =
-      connect(m_textFld, SIGNAL(editingFinished()), this, SLOT(onChange()));
-  m_layout->addWidget(m_textFld);
 
+  bool ret = true;
+  if (param->isMultiLineEnabled()) {
+    m_multiTextFld = new component::MyTextEdit(name, this);
+    m_multiTextFld->setFixedHeight(80);
+    m_multiTextFld->setAcceptRichText(false);
+    m_multiTextFld->setStyleSheet(
+        "background:white;\ncolor:black;\nborder:1 solid black;");
+    ret = ret &&
+          connect(m_multiTextFld, SIGNAL(edited()), this, SLOT(onChange()));
+    m_layout->addWidget(m_multiTextFld);
+  } else {
+    m_textFld = new LineEdit(name, this);
+    m_textFld->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
+    ret = ret &&
+          connect(m_textFld, SIGNAL(editingFinished()), this, SLOT(onChange()));
+    m_layout->addWidget(m_textFld);
+  }
   setLayout(m_layout);
   assert(ret);
 }
@@ -1413,12 +1472,17 @@ StringParamField::StringParamField(QWidget *parent, QString name,
 //-----------------------------------------------------------------------------
 
 void StringParamField::onChange() {
-  std::wstring value = m_textFld->text().toStdWString();
-  TUndo *undo        = 0;
+  std::wstring value;
+  if (m_multiTextFld)
+    value = m_multiTextFld->toPlainText().toStdWString();
+  else
+    value     = m_textFld->text().toStdWString();
+  TUndo *undo = 0;
+
+  if (!m_actualParam || m_actualParam->getValue() == value) return;
 
-  TStringParamP stringParam = m_actualParam;
-  if (stringParam && stringParam->getValue() != value)
-    undo = new StringParamFieldUndo(stringParam, m_interfaceName,
+  if (m_actualParam->getValue() != value)
+    undo = new StringParamFieldUndo(m_actualParam, m_interfaceName,
                                     ParamField::m_fxHandleStat);
 
   m_actualParam->setValue(value);
@@ -1447,13 +1511,147 @@ void StringParamField::update(int frame) {
   if (!m_actualParam || !m_currentParam) return;
   QString str;
   QString strValue = str.fromStdWString(m_actualParam->getValue());
-  if (m_textFld->text() == strValue) return;
-  m_textFld->setText(strValue);
 
-  // Faccio in modo che il cursore sia sulla prima cifra, cosi' se la stringa
-  // da visualizzare e' piu' lunga del campo le cifre che vengono troncate sono
-  // le ultime e non le prime (dovrebbero essere quelle dopo la virgola).
-  m_textFld->setCursorPosition(0);
+  if (m_textFld) {
+    if (m_textFld->text() == strValue) return;
+    m_textFld->setText(strValue);
+
+    // Faccio in modo che il cursore sia sulla prima cifra, cosi' se la stringa
+    // da visualizzare e' piu' lunga del campo le cifre che vengono troncate
+    // sono
+    // le ultime e non le prime (dovrebbero essere quelle dopo la virgola).
+    m_textFld->setCursorPosition(0);
+  } else {
+    if (m_multiTextFld->toPlainText() == strValue) return;
+    m_multiTextFld->setPlainText(strValue);
+  }
+}
+
+//=============================================================================
+// FontParamField
+//-----------------------------------------------------------------------------
+
+FontParamField::FontParamField(QWidget *parent, QString name,
+                               const TFontParamP &param)
+    : ParamField(parent, name, param) {
+  m_paramName = QString::fromStdString(param->getName());
+
+  m_fontCombo  = new QFontComboBox(this);
+  m_styleCombo = new QComboBox(this);
+  m_sizeField  = new IntField(this, false);
+
+  m_sizeField->setRange(1, 500);
+  m_sizeField->enableSlider(false);
+
+  m_layout->addWidget(m_fontCombo);
+  m_layout->addSpacing(5);
+  m_layout->addWidget(new QLabel(tr("Style:"), this), 0,
+                      Qt::AlignRight | Qt::AlignVCenter);
+  m_layout->addWidget(m_styleCombo);
+  m_layout->addSpacing(5);
+  m_layout->addWidget(new QLabel(tr("Size:"), this), 0,
+                      Qt::AlignRight | Qt::AlignVCenter);
+  m_layout->addWidget(m_sizeField);
+
+  m_layout->addStretch();
+
+  setLayout(m_layout);
+
+  bool ret = true;
+  ret = ret && connect(m_fontCombo, &QFontComboBox::currentFontChanged, this,
+                       &FontParamField::findStyles);
+  ret = ret && connect(m_fontCombo, &QFontComboBox::currentFontChanged, this,
+                       &FontParamField::onChange);
+  ret = ret && connect(m_styleCombo, SIGNAL(activated(const QString &)), this,
+                       SLOT(onChange()));
+  ret = ret && connect(m_sizeField, SIGNAL(valueChanged(bool)), this,
+                       SLOT(onSizeChange(bool)));
+  assert(ret);
+
+  findStyles(m_fontCombo->currentFont());
+}
+
+//-----------------------------------------------------------------------------
+
+void FontParamField::findStyles(const QFont &font) {
+  QFontDatabase fontDatabase;
+  QString currentItem = m_styleCombo->currentText();
+  m_styleCombo->clear();
+
+  QString style;
+  foreach (style, fontDatabase.styles(font.family()))
+    m_styleCombo->addItem(style);
+
+  int styleIndex = m_styleCombo->findText(currentItem);
+
+  if (styleIndex == -1)
+    m_styleCombo->setCurrentIndex(0);
+  else
+    m_styleCombo->setCurrentIndex(styleIndex);
+}
+
+//-----------------------------------------------------------------------------
+
+void FontParamField::onSizeChange(bool isDragging) {
+  if (isDragging) return;
+  onChange();
+}
+
+//-----------------------------------------------------------------------------
+
+void FontParamField::onChange() {
+  QString family = m_fontCombo->currentFont().family();
+  QString style  = m_styleCombo->currentText();
+
+  int size = m_sizeField->getValue();
+  int min, max;
+  m_sizeField->getRange(min, max);
+  if (size < min) size = min;
+
+  QFontDatabase fontDatabase;
+  QFont font = fontDatabase.font(family, style, 10);
+  font.setPixelSize(size);
+
+  TUndo *undo = 0;
+
+  TFontParamP fontParam = m_actualParam;
+  QFont currentFont;
+  currentFont.fromString(QString::fromStdWString(fontParam->getValue()));
+  if (fontParam && currentFont != font)
+    undo = new FontParamFieldUndo(fontParam, m_interfaceName,
+                                  ParamField::m_fxHandleStat);
+
+  m_actualParam->setValue(font.toString().toStdWString());
+  emit currentParamChanged();
+  m_currentParam->setValue(font.toString().toStdWString());
+  emit actualParamChanged();
+
+  if (undo) TUndoManager::manager()->add(undo);
+}
+
+//-----------------------------------------------------------------------------
+
+void FontParamField::setParam(const TParamP &current, const TParamP &actual,
+                              int frame) {
+  m_currentParam = current;
+  m_actualParam  = actual;
+  assert(m_currentParam);
+  assert(m_actualParam);
+  update(frame);
+}
+
+//-----------------------------------------------------------------------------
+
+void FontParamField::update(int frame) {
+  if (!m_actualParam || !m_currentParam) return;
+  QFont font;
+  font.fromString(QString::fromStdWString(m_actualParam->getValue()));
+
+  if (m_fontCombo->currentText() != font.family())
+    m_fontCombo->setCurrentFont(font);
+
+  m_styleCombo->setCurrentText(font.styleName());
+  m_sizeField->setValue(font.pixelSize());
 }
 
 //=============================================================================
@@ -1660,6 +1858,8 @@ ParamField *ParamField::create(QWidget *parent, QString name,
     return new StringParamField(parent, name, stringParam);
   else if (TToneCurveParamP toneCurveParam = param)
     return new ToneCurveParamField(parent, name, toneCurveParam);
+  else if (TFontParamP fontParam = param)
+    return new FontParamField(parent, name, fontParam);
   else
     return 0;
 }