Just adding a val into a template doesn't automatically make it a constructor parameter. To do that, the constructor itself also needs to be adjusted. Luckily we have quasiquotes, which greatly simplify this task in comparison with manual tree construction.
case q"$mods class $name[..$tparams](..$first)(...$rest) extends ..$parents { $self => ..$body }" :: Nil =>
val CASEACCESSOR = (1 << 24).toLong.asInstanceOf[FlagSet]
val PARAMACCESSOR = (1 << 29).toLong.asInstanceOf[FlagSet]
val helloMods = Modifiers(CASEACCESSOR | PARAMACCESSOR | DEFAULTPARAM)
val helloVal = q"""$helloMods val x: String = "hello macro!""""
q"$mods class $name[..$tparams](..$first, $helloVal)(...$rest) extends ..$parents { $self => ..$body }"
Note a couple of quirks: 1) we need to set CASEACCESSOR and PARAMACCESSOR flags that aren't present in the official API in order to avoid crash in Salat, 2) we need to set DEFAULTPARAM in order to make sure that scalac recognizes our default parameter as default, 3) default parameters can't have their types inferred, so we need to explicitly provide String here.